/* This is the header file of the Parma Polyhedra Library.
   Copyright (C) 2001-2009 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 3 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 NDEBUG
# undef NDEBUG
#endif

#ifdef __STDC_LIMIT_MACROS
# define PPL_SAVE_STDC_LIMIT_MACROS __STDC_LIMIT_MACROS
#endif

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


/* Unique (nonzero) code for the IEEE 754 Single Precision
   floating point format.  */
#define PPL_FLOAT_IEEE754_SINGLE 1

/* Unique (nonzero) code for the IEEE 754 Double Precision
   floating point format.  */
#define PPL_FLOAT_IEEE754_DOUBLE 2

/* Unique (nonzero) code for the IEEE 754 Quad Precision
   floating point format.  */
#define PPL_FLOAT_IEEE754_QUAD 3

/* Unique (nonzero) code for the Intel Double-Extended
   floating point format.  */
#define PPL_FLOAT_INTEL_DOUBLE_EXTENDED 4


/* Define if building universal (internal helper macro) */
/* #undef AC_APPLE_UNIVERSAL_BUILD */

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

/* Define to 1 if you have the <glpk/glpk.h> header file. */
/* #undef PPL_HAVE_GLPK_GLPK_H */

/* Define to 1 if you have the <glpk.h> header file. */
/* #undef PPL_HAVE_GLPK_H */

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

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

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

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

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

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

/* Define to 1 if you have the `setitimer' function. */
#define HAVE_SETITIMER 1

/* Define to 1 if the system has the type `siginfo_t'. */
#define HAVE_SIGINFO_T 1

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

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

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

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

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

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

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

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

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

/* Define to 1 if the system has the type `timeval'. */
#define PPL_HAVE_TIMEVAL 1

/* Define to 1 if typeof works with your compiler. */
#define PPL_HAVE_TYPEOF 1

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

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

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

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

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

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

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

/* Define to the sub-directory in which libtool stores uninstalled libraries.
   */
#define LT_OBJDIR ".libs/"

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

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

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

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

/* Define to the version of this package. */
#define PPL_PACKAGE_VERSION "0.10.2"

/* ABI-breaking extra assertions are enabled when this is defined. */
/* #undef PPL_ABI_BREAKING_EXTRA_DEBUG */

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

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

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

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

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

/* The unique code of the binary format of C++ doubles, if supported;
   undefined otherwise. */
#define PPL_CXX_DOUBLE_BINARY_FORMAT PPL_FLOAT_IEEE754_DOUBLE

/* Not zero if C++ supports exact output for doubles. */
#define PPL_CXX_DOUBLE_EXACT_OUTPUT 1

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

/* Not zero if C++ supports exact output for floats. */
#define PPL_CXX_FLOAT_EXACT_OUTPUT 1

/* Not zero if the C++ compiler has the remainder bug. */
#define PPL_CXX_HAS_REMAINDER_BUG 1

/* The unique code of the binary format of C++ long doubles, if supported;
   undefined otherwise. */
#define PPL_CXX_LONG_DOUBLE_BINARY_FORMAT PPL_FLOAT_INTEL_DOUBLE_EXTENDED

/* Not zero if C++ supports exact output for long doubles. */
#define PPL_CXX_LONG_DOUBLE_EXACT_OUTPUT 1

/* Not zero if the C++ compiler provides long double numbers that have bigger
   range or precision than double. */
#define PPL_CXX_PROVIDES_PROPER_LONG_DOUBLE 1

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

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

/* Not zero if the the IEEE inexact flag is supported in C++. */
#define PPL_CXX_SUPPORTS_IEEE_INEXACT_FLAG 1

/* Not zero if it is possible to limit memory using setrlimit(). */
#define PPL_CXX_SUPPORTS_LIMITING_MEMORY 1

/* Defined if floating point arithmetics may use the 387 unit. */
#define PPL_FPMATH_MAY_USE_387 1

/* Defined if floating point arithmetics may use the SSE instruction set. */
#define PPL_FPMATH_MAY_USE_SSE 1

/* Defined if GLPK provides glp_term_hook(). */
/* #undef PPL_GLPK_HAS_GLP_TERM_HOOK */

/* Defined if GLPK provides glp_term_out(). */
/* #undef PPL_GLPK_HAS_GLP_TERM_OUT */

/* Defined if GLPK provides lib_set_print_hook(). */
/* #undef PPL_GLPK_HAS_LIB_SET_PRINT_HOOK */

/* Defined if GLPK provides _glp_lib_print_hook(). */
/* #undef PPL_GLPK_HAS__GLP_LIB_PRINT_HOOK */

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

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

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

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

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

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

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

/* Defined if the Parma Watchdog Library is enabled. */
#define PPL_WATCHDOG_LIBRARY_ENABLED 1

/* The size of `char', as computed by sizeof. */
#define PPL_SIZEOF_CHAR 1

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

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

/* The size of `fp', as computed by sizeof. */
#define PPL_SIZEOF_FP 8

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

/* The size of `int*', as computed by sizeof. */
#define PPL_SIZEOF_INTP 8

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

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

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

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

/* The size of `short', as computed by sizeof. */
#define PPL_SIZEOF_SHORT 2

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

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

/* Define PPL_WORDS_BIGENDIAN to 1 if your processor stores words with the most
   significant byte first (like Motorola and SPARC, unlike Intel). */
#if defined AC_APPLE_UNIVERSAL_BUILD
# if defined __BIG_ENDIAN__
#  define PPL_WORDS_BIGENDIAN 1
# endif
#else
# ifndef PPL_WORDS_BIGENDIAN
/* #  undef PPL_WORDS_BIGENDIAN */
# endif
#endif

/* When defined and libstdc++ is used, it is used in debug mode. */
/* #undef _GLIBCXX_DEBUG */

/* When defined and libstdc++ is used, it is used in pedantic debug mode. */
/* #undef _GLIBCXX_DEBUG_PEDANTIC */

/* 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

/* Define to __typeof__ if your compiler spells it that way. */
/* #undef typeof */


#if defined(PPL_NDEBUG) && !defined(NDEBUG)
# define NDEBUG PPL_NDEBUG
#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.  Moreover we need to define
   __STDC_LIMIT_MACROS before the first inclusion of <stdint.h>
   in order to have the macros defined also in C++.  */

#ifdef PPL_HAVE_STDINT_H
# ifndef __STDC_LIMIT_MACROS
#  define __STDC_LIMIT_MACROS 1
# endif
# include <stdint.h>
#endif

#ifdef PPL_HAVE_INTTYPES_H
# include <inttypes.h>
#endif

/* 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 10

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

/*! \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.10.2"

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.
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 predefined 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 // defined(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 // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
namespace Implementation {
} // namespace Implementation

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Data and functions related to language interfaces.
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
namespace Interfaces {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Data and functions related to the C language interface.
/*! \ingroup PPL_C_interface */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
namespace C {

} // namespace C

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Data and functions related to the Java language interface.
/*! \ingroup PPL_Java_interface */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
namespace Java {

} // namespace Java

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Data and functions related to the OCaml language interface.
/*! \ingroup PPL_OCaml_interface */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
namespace OCaml {

} // namespace OCaml

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Data and functions related to the Prolog language interfaces.
/*! \ingroup PPL_Prolog_interface */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
namespace Prolog {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Data and functions related to the Ciao Prolog language interface.
/*! \ingroup PPL_Prolog_interface */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
namespace Ciao {

} // namespace Ciao

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Data and functions related to the GNU Prolog language interface.
/*! \ingroup PPL_Prolog_interface */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
namespace GNU {

} // namespace GNU

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Data and functions related to the SICStus language interface.
/*! \ingroup PPL_Prolog_interface */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
namespace SICStus {

} // namespace SICStus

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Data and functions related to the SWI-Prolog language interface.
/*! \ingroup PPL_Prolog_interface */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
namespace SWI {

} // namespace SWI

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Data and functions related to the XSB language interface.
/*! \ingroup PPL_Prolog_interface */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
namespace XSB {

} // namespace XSB

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Data and functions related to the YAP language interface.
/*! \ingroup PPL_Prolog_interface */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
namespace YAP {

} // namespace YAP

} // namespace Prolog

} // namespace Interfaces

} // 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/Interval_Info.types.hh line 1. */


namespace Parma_Polyhedra_Library {

template <typename Policy>
class Interval_Info_Null;

template <typename T, typename Policy>
class Interval_Info_Bitset;

} // namespace Parma_Polyhedra_Library

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


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


namespace Parma_Polyhedra_Library {

class stdiobuf;

} // namespace Parma_Polyhedra_Library

/* Automatically generated from PPL source file ../src/stdiobuf.defs.hh line 27. */
#include <cstdio>
#include <streambuf>

class Parma_Polyhedra_Library::stdiobuf
  : public std::basic_streambuf<char, std::char_traits<char> > {
public:
  //! Constructor.
  stdiobuf(FILE* file);

protected:
  /*! \brief
    Gets a character in case of underflow.

    \remarks
    Specified by ISO/IEC 14882:1998: 27.5.2.4.3.
  */
  virtual int_type underflow();

  /*! \brief
    In case of underflow, gets a character and advances the next pointer.

    \remarks
    Specified by ISO/IEC 14882:1998: 27.5.2.4.3.
  */
  virtual int_type uflow();

  /*! \brief
    Gets a sequence of characters.

    \remarks
    Specified by ISO/IEC 14882:1998: 27.5.2.4.3.
  */
  virtual std::streamsize xsgetn(char_type* s, std::streamsize n);

  /*! \brief
    Puts character back in case of backup underflow.

    \remarks
    Specified by ISO/IEC 14882:1998: 27.5.2.4.4.
  */
  virtual int_type pbackfail(int_type c = traits_type::eof());

  /*! \brief
    Writes a sequence of characters.

    \remarks
    Specified by ISO/IEC 14882:1998: 27.5.2.4.5.
  */
  virtual std::streamsize xsputn(const char_type* s, std::streamsize n);

  /*! \brief
    Writes a character in case of overflow.

    Specified by ISO/IEC 14882:1998: 27.5.2.4.5.
  */
  virtual int_type overflow(int_type c);

  /*! \brief
    Synchronizes the stream buffer.

    Specified by ISO/IEC 14882:1998: 27.5.2.4.2.
  */
  virtual int sync();

private:
  //! Character type of the streambuf.
  typedef char char_type;

  //! Traits type of the streambuf.
  typedef std::char_traits<char_type> traits_type;

  //! Integer type of the streambuf.
  typedef traits_type::int_type int_type;

  //! The encapsulated stdio file.
  FILE* fp;

  //! Buffer for the last character read.
  int_type ungetc_buf;
};

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


namespace Parma_Polyhedra_Library {

inline
stdiobuf::stdiobuf(FILE* file)
  : fp(file), ungetc_buf(traits_type::eof()) {
}

} // namespace Parma_Polyhedra_Library

/* Automatically generated from PPL source file ../src/stdiobuf.defs.hh line 109. */

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


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


namespace Parma_Polyhedra_Library {

class c_streambuf;

} // namespace Parma_Polyhedra_Library

/* Automatically generated from PPL source file ../src/c_streambuf.defs.hh line 27. */
#include <streambuf>

class Parma_Polyhedra_Library::c_streambuf
  : public std::basic_streambuf<char, std::char_traits<char> > {
public:
  //! Constructor.
  c_streambuf();
  virtual ~c_streambuf();

protected:
  /*! \brief
    Gets a character in case of underflow.

    \remarks
    Specified by ISO/IEC 14882:1998: 27.5.2.4.3.
  */
  int_type underflow();

  /*! \brief
    In case of underflow, gets a character and advances the next pointer.

    \remarks
    Specified by ISO/IEC 14882:1998: 27.5.2.4.3.
  */
  int_type uflow();

  /*! \brief
    Gets a sequence of characters.

    \remarks
    Specified by ISO/IEC 14882:1998: 27.5.2.4.3.
  */
  std::streamsize xsgetn(char_type* s, std::streamsize n);

  /*! \brief
    Puts character back in case of backup underflow.

    \remarks
    Specified by ISO/IEC 14882:1998: 27.5.2.4.4.
  */
  int_type pbackfail(int_type c = traits_type::eof());

  /*! \brief
    Writes a sequence of characters.

    \remarks
    Specified by ISO/IEC 14882:1998: 27.5.2.4.5.
  */
  std::streamsize xsputn(const char_type* s, std::streamsize n);

  /*! \brief
    Writes a character in case of overflow.

    Specified by ISO/IEC 14882:1998: 27.5.2.4.5.
  */
  int_type overflow(int_type c);

  /*! \brief
    Synchronizes the stream buffer.

    Specified by ISO/IEC 14882:1998: 27.5.2.4.2.
  */
  int sync();

private:
  //! Character type of the streambuf.
  typedef char char_type;

  //! Traits type of the streambuf.
  typedef std::char_traits<char_type> traits_type;

  //! Integer type of the streambuf.
  typedef traits_type::int_type int_type;

  //! Buffer for the last character read.
  int_type ungetc_buf;

  //! Buffer for next character
  int_type nextc_buf;

  virtual size_t cb_read(char *, size_t) {
    return 0;
  }
  virtual size_t cb_write(const char *, size_t) {
    return 0;
  }
  virtual int cb_sync() {
    return 0;
  }
  virtual int cb_flush() {
    return 0;
  }
};

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


namespace Parma_Polyhedra_Library {

inline
c_streambuf::c_streambuf()
  : ungetc_buf(traits_type::eof()), nextc_buf(traits_type::eof()) {
}

inline
c_streambuf::~c_streambuf() {
}

} // namespace Parma_Polyhedra_Library

/* Automatically generated from PPL source file ../src/c_streambuf.defs.hh line 122. */

/* 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/Init.defs.hh line 1. */
/* Init class declaration.
*/


/* 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/fpu.types.hh line 1. */


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

namespace Parma_Polyhedra_Library {

enum fpu_rounding_direction_type {};
enum fpu_rounding_control_word_type {};

} // namespace Parma_Polyhedra_Library

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

namespace Parma_Polyhedra_Library {

/*! \brief
  Sets the FPU rounding mode so that the PPL abstractions based on
  floating point numbers work correctly.

  This is performed automatically at initialization-time.  Calling
  this function is needed only if restore_pre_PPL_rounding() has been
  previously called.
*/
void set_rounding_for_PPL();

/*! \brief
  Sets the FPU rounding mode as it was before initialization of the PPL.

  After calling this function it is absolutely necessary to call
  set_rounding_for_PPL() before using any PPL abstractions based on
  floating point numbers.
  This is performed automatically at finalization-time.
*/
void restore_pre_PPL_rounding();

} // namespace Parma_Polyhedra_Library

#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 // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
class Parma_Polyhedra_Library::Init {
public:
  //! Initializes the PPL.
  Init();

  //! Finalizes the PPL.
  ~Init();

private:
  //! Count the number of objects created.
  static unsigned int count;
  static fpu_rounding_direction_type old_rounding_direction;

  friend void set_rounding_for_PPL();
  friend void restore_pre_PPL_rounding();
};

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


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


/* 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
/*! \brief
  No-op function that allows to avoid unused variable warnings from
  the compiler.
*/
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename T>
inline void
used(const T&) {
}

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \brief
  No-op function that force the compiler to store the argument and
  to reread it from memory if needed (thus preventing CSE).
*/
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename T>
inline void
cc_flush(const T& x) {
#if defined(__GNUC__) || defined(__INTEL_COMPILER)
  __asm__ __volatile__ ("" : "+m" (const_cast<T&>(x)));
#else
  // FIXME: is it possible to achieve the same effect in a portable way?
  used(x);
#endif
}

#ifndef PPL_SUPPRESS_UNINIT_WARNINGS
#define PPL_SUPPRESS_UNINIT_WARNINGS 1
#endif

#ifndef PPL_SUPPRESS_UNINITIALIZED_WARNINGS
#define PPL_SUPPRESS_UNINITIALIZED_WARNINGS 1
#endif

#if PPL_SUPPRESS_UNINITIALIZED_WARNINGS
template <typename T>
struct Suppress_Uninitialized_Warnings_Type {
  typedef T synonym;
};

#define PPL_UNINITIALIZED(type, name)                                   \
  type name = Suppress_Uninitialized_Warnings_Type<type>::synonym ()
#else
#define PPL_UNINITIALIZED(type, name)           \
  type name
#endif

} // namespace Parma_Polyhedra_Library

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

namespace Parma_Polyhedra_Library {

//! Initializes the FPU control functions.
void
fpu_initialize_control_functions();

//! 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 PPL_CAN_CONTROL_FPU

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


#include <csetjmp>
#include <csignal>

#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 PPL_FPU_TONEAREST     0
#define PPL_FPU_DOWNWARD      0x400
#define PPL_FPU_UPWARD        0x800
#define PPL_FPU_TOWARDZERO    0xc00

#define FPU_ROUNDING_MASK 0xc00

#define SSE_INEXACT       0x20

#define PPL_FPU_CONTROL_DEFAULT_BASE 0x37f
#define PPL_SSE_CONTROL_DEFAULT_BASE 0x1f80

// This MUST be congruent with the definition of ROUND_DIRECT
#define PPL_FPU_CONTROL_DEFAULT \
  (PPL_FPU_CONTROL_DEFAULT_BASE | PPL_FPU_UPWARD)
#define PPL_SSE_CONTROL_DEFAULT \
  (PPL_SSE_CONTROL_DEFAULT_BASE | (PPL_FPU_UPWARD << 3))

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) : : "memory");
  return cw;
}

inline void
fpu_set_control(int c) {
  unsigned short cw = static_cast<unsigned short>(c);
  __asm__ __volatile__ ("fldcw %0" : : "m" (*&cw) : "memory");
}

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

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

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

#ifdef PPL_FPMATH_MAY_USE_SSE
inline void
sse_set_control(unsigned int cw) {
  __asm__ __volatile__ ("ldmxcsr %0" : : "m" (*&cw) : "memory");
}

inline unsigned int
sse_get_control() {
  unsigned int cw;
  __asm__ __volatile__ ("stmxcsr %0" : "=m" (*&cw) : : "memory");
  return cw;
}
#endif

inline void
fpu_initialize_control_functions() {
#ifdef PPL_FPMATH_MAY_USE_SSE
  extern void detect_sse_unit();
  detect_sse_unit();
#endif
}

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

inline void
fpu_set_rounding_direction(fpu_rounding_direction_type dir) {
#ifdef PPL_FPMATH_MAY_USE_387
  fpu_set_control(PPL_FPU_CONTROL_DEFAULT_BASE | dir);
#endif
#ifdef PPL_FPMATH_MAY_USE_SSE
  extern bool have_sse_unit;
  if (have_sse_unit)
    sse_set_control(PPL_SSE_CONTROL_DEFAULT_BASE | (dir << 3));
#endif
}

inline fpu_rounding_control_word_type
fpu_save_rounding_direction(fpu_rounding_direction_type dir) {
#ifdef PPL_FPMATH_MAY_USE_387
  fpu_set_control(PPL_FPU_CONTROL_DEFAULT_BASE | dir);
#endif
#ifdef PPL_FPMATH_MAY_USE_SSE
  extern bool have_sse_unit;
  if (have_sse_unit)
    sse_set_control(PPL_SSE_CONTROL_DEFAULT_BASE | (dir << 3));
#endif
  return static_cast<fpu_rounding_control_word_type>(0);
}

inline void
fpu_reset_inexact() {
#ifdef PPL_FPMATH_MAY_USE_387
  fpu_clear_exceptions();
#endif
#ifdef PPL_FPMATH_MAY_USE_SSE
  // NOTE: on entry to this function the current rounding mode
  // has to be the default one.
  extern bool have_sse_unit;
  if (have_sse_unit)
    sse_set_control(PPL_SSE_CONTROL_DEFAULT);
#endif
}

inline void
fpu_restore_rounding_direction(fpu_rounding_control_word_type) {
#ifdef PPL_FPMATH_MAY_USE_387
  fpu_set_control(PPL_FPU_CONTROL_DEFAULT);
#endif
#ifdef PPL_FPMATH_MAY_USE_SSE
  extern bool have_sse_unit;
  if (have_sse_unit)
    sse_set_control(PPL_SSE_CONTROL_DEFAULT);
#endif
}

inline int
fpu_check_inexact() {
#ifdef PPL_FPMATH_MAY_USE_387
  if (fpu_get_status() & FPU_INEXACT)
    return 1;
#endif
#ifdef PPL_FPMATH_MAY_USE_SSE
  extern bool have_sse_unit;
  if (have_sse_unit && (sse_get_control() & SSE_INEXACT))
    return 1;
#endif
  return 0;
}

} // namespace Parma_Polyhedra_Library

/* Automatically generated from PPL source file ../src/fpu.defs.hh line 81. */
#elif defined(PPL_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 PPL_HAVE_IEEEFP_H
#include <ieeefp.h>

#define PPL_FPU_TONEAREST  ((int) FP_RN)
#define PPL_FPU_UPWARD     ((int) FP_RP)
#define PPL_FPU_DOWNWARD   ((int) FP_RM)
#define PPL_FPU_TOWARDZERO ((int) FP_RZ)

namespace Parma_Polyhedra_Library {

inline void
fpu_initialize_control_functions() {
}

inline fpu_rounding_direction_type
fpu_get_rounding_direction() {
  return static_cast<fpu_rounding_direction_type>(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 static_cast<fpu_rounding_control_word_type>(fpsetround((fp_rnd) dir));
}

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

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(PPL_HAVE_IEEEFP_H)

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


#ifdef PPL_HAVE_FENV_H
#include <fenv.h>
#include <stdexcept>

#ifdef FE_TONEAREST
#define PPL_FPU_TONEAREST FE_TONEAREST
#endif
#ifdef FE_UPWARD
#define PPL_FPU_UPWARD FE_UPWARD
#endif
#ifdef FE_DOWNWARD
#define PPL_FPU_DOWNWARD FE_DOWNWARD
#endif
#ifdef FE_TOWARDZERO
#define PPL_PPL_FPU_TOWARDZERO FE_TOWARDZERO
#endif

namespace Parma_Polyhedra_Library {

inline void
fpu_initialize_control_functions() {
  int old = fegetround();
  if (fesetround(PPL_FPU_DOWNWARD) != 0
      || fesetround(PPL_FPU_UPWARD) != 0
      || fesetround(old) != 0)
    throw std::logic_error("PPL configuration error:"
			   " PPL_CAN_CONTROL_FPU evaluates to true,"
			   " but fesetround() returns nonzero.");
}

inline fpu_rounding_direction_type
fpu_get_rounding_direction() {
  return static_cast<fpu_rounding_direction_type>(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_control_word_type old
    = static_cast<fpu_rounding_control_word_type>(fegetround());
  fesetround(dir);
  return old;
}

inline void
fpu_reset_inexact() {
#if PPL_CXX_SUPPORTS_IEEE_INEXACT_FLAG
  feclearexcept(FE_INEXACT);
#endif
}

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

inline int
fpu_check_inexact() {
#if PPL_CXX_SUPPORTS_IEEE_INEXACT_FLAG
  return fetestexcept(FE_INEXACT) != 0;
#else
  return -1;
#endif
}

} // namespace Parma_Polyhedra_Library

#endif // !defined(PPL_HAVE_FENV_H)

/* Automatically generated from PPL source file ../src/fpu.defs.hh line 88. */
#else
#error "PPL_CAN_CONTROL_FPU evaluates to true, but why?"
#endif

#else // !PPL_CAN_CONTROL_FPU

/* 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 void
fpu_initialize_control_functions() {
  throw std::logic_error("PPL::fpu_initialize_control_functions():"
			 " cannot control the FPU");
}

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

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

inline int
fpu_save_rounding_direction(int) {
  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 void
fpu_restore_rounding_direction(int) {
  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 95. */

#endif // !PPL_CAN_CONTROL_FPU

/* 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 {

  //! \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,

  VC_MASK = 48
};

//! Extracts the class part of \p r (normal, minus/plus infinity or nan).
Result classify(Result r);

//! Returns <CODE>true</CODE> if and only if the class or \p r is not normal.
bool is_special(Result r);

} // namespace Parma_Polyhedra_Library

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


namespace Parma_Polyhedra_Library {

/*! \relates Parma_Polyhedra_Library::Result */
inline Result
classify(Result r) {
  return static_cast<Result>(r & VC_MASK);
}

/*! \relates Parma_Polyhedra_Library::Result */
inline bool
is_special(Result r) {
  return classify(r) != VC_NORMAL;
}

} // namespace Parma_Polyhedra_Library

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

/* 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 = 0,

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

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

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

  ROUND_DIRECT = ROUND_UP,
  ROUND_INVERSE = ROUND_DOWN,

  ROUND_DIR_MASK = 7,

  ROUND_FPU_CHECK_INEXACT = 8,

  ROUND_CHECK = ROUND_DIRECT | ROUND_FPU_CHECK_INEXACT
};

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

Rounding_Dir round_dir(Rounding_Dir dir);
bool round_down(Rounding_Dir dir);
bool round_up(Rounding_Dir dir);
bool round_ignore(Rounding_Dir dir);
bool round_direct(Rounding_Dir dir);
bool round_inverse(Rounding_Dir dir);

bool round_fpu_check_inexact(Rounding_Dir dir);

fpu_rounding_direction_type round_fpu_dir(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.
*/


#include <cassert>

namespace Parma_Polyhedra_Library {

inline Rounding_Dir
round_dir(Rounding_Dir dir) {
  return static_cast<Rounding_Dir>(dir & ROUND_DIR_MASK);
}

inline bool
round_down(Rounding_Dir dir) {
  return round_dir(dir) == ROUND_DOWN;
}

inline bool
round_up(Rounding_Dir dir) {
  return round_dir(dir) == ROUND_UP;
}

inline bool
round_ignore(Rounding_Dir dir) {
  return round_dir(dir) == ROUND_IGNORE;
}

inline bool
round_direct(Rounding_Dir dir) {
  return round_dir(dir) == ROUND_DIRECT;
}

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

inline bool
round_fpu_check_inexact(Rounding_Dir dir) {
  return dir & ROUND_FPU_CHECK_INEXACT;
}

#if PPL_CAN_CONTROL_FPU

inline fpu_rounding_direction_type
round_fpu_dir(Rounding_Dir dir) {
  switch (round_dir(dir)) {
  case ROUND_UP:
    return static_cast<fpu_rounding_direction_type>(PPL_FPU_UPWARD);
  case ROUND_DOWN:
    return static_cast<fpu_rounding_direction_type>(PPL_FPU_DOWNWARD);
  default:
    assert(false);
    return static_cast<fpu_rounding_direction_type>(PPL_FPU_UPWARD);
  }
}

#undef PPL_FPU_DOWNWARD
#undef PPL_FPU_TONEAREST
#undef PPL_FPU_TOWARDZERO
#undef PPL_FPU_UPWARD

#endif

/*! \relates Parma_Polyhedra_Library::Rounding_Dir */
inline Rounding_Dir
inverse(Rounding_Dir dir) {
  Rounding_Dir d = round_dir(dir);
  switch (d) {
  case ROUND_UP:
    d = ROUND_DOWN;
    break;
  case ROUND_DOWN:
    d = ROUND_UP;
    break;
  default:
    assert(false);
    /* Fall through */
  case ROUND_IGNORE:
    return dir;
  }
  return static_cast<Rounding_Dir>((dir & ~ROUND_DIR_MASK) | d);
}

} // namespace Parma_Polyhedra_Library

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


/* Automatically generated from PPL source file ../src/Init.inlines.hh line 28. */

namespace Parma_Polyhedra_Library {

inline void
set_rounding_for_PPL() {
#if PPL_CAN_CONTROL_FPU
    fpu_set_rounding_direction(round_fpu_dir(ROUND_DIRECT));
#endif
}

inline void
restore_pre_PPL_rounding() {
#if PPL_CAN_CONTROL_FPU
  fpu_set_rounding_direction(Init::old_rounding_direction);
#endif
}

} // namespace Parma_Polyhedra_Library

/* Automatically generated from PPL source file ../src/Init.defs.hh line 84. */


/* Automatically generated from PPL source file ../src/initializer.hh line 27. */

#ifndef PPL_NO_AUTOMATIC_INITIALIZATION
namespace {

Parma_Polyhedra_Library::Init Parma_Polyhedra_Library_initializer;

} // namespace
#else
namespace {

Parma_Polyhedra_Library::Init* Parma_Polyhedra_Library_initializer_p;

} // namespace
#endif

namespace Parma_Polyhedra_Library {

//! Initializes the library.
inline void
initialize() {
#ifdef PPL_NO_AUTOMATIC_INITIALIZATION
  if (Parma_Polyhedra_Library_initializer_p == 0)
    Parma_Polyhedra_Library_initializer_p = new Init();
#endif
}

//! Finalizes the library.
inline void
finalize() {
#ifdef PPL_NO_AUTOMATIC_INITIALIZATION
  assert(Parma_Polyhedra_Library_initializer_p != 0);
  delete Parma_Polyhedra_Library_initializer_p;
  Parma_Polyhedra_Library_initializer_p = 0;
#endif
}

} //namespace Parma_Polyhedra_Library

/* 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.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/Linear_Row.types.hh line 1. */


namespace Parma_Polyhedra_Library {

class Linear_Row;

} // 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_Number.types.hh line 1. */


/* 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 // defined(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 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/checked.defs.hh line 1. */
/* Abstract checked arithmetic function container
*/


#include <iostream>
#include <gmpxx.h>
/* Automatically generated from PPL source file ../src/mp_std_bits.defs.hh line 1. */
/* Declarations of specializations of std:: objects for
   multi-precision types.  This will become obsolete when GMP and MPFR
   will provide the specializations by themselves.
*/


#include <gmpxx.h>
#include <limits>

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Swaps \p x with \p y.
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
void swap(mpz_class& x, mpz_class& y);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Swaps \p x with \p y.
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
void swap(mpq_class& x, mpq_class& y);

namespace std {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Specialization of std::numeric_limits.
#endif // defined(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 tininess_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 // defined(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 tininess_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/mp_std_bits.inlines.hh line 1. */
/* Definitions of specializations of std:: functions and methods for
   multi-precision types.  This will become obsolete when GMP and MPFR
   will provide the specializations by themselves.
*/


inline void
swap(mpz_class& x, mpz_class& y) {
  mpz_swap(x.get_mpz_t(), y.get_mpz_t());
}

inline void
swap(mpq_class& x, mpq_class& y) {
  mpq_swap(x.get_mpq_t(), y.get_mpq_t());
}

/* Automatically generated from PPL source file ../src/mp_std_bits.defs.hh line 168. */

/* Automatically generated from PPL source file ../src/Temp.defs.hh line 1. */
/* Temp_* classes declarations.
*/


/* Automatically generated from PPL source file ../src/meta_programming.hh line 1. */
/* Metaprogramming utilities.
*/


#include <gmpxx.h>

namespace Parma_Polyhedra_Library {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \brief
  Declares a per-class constant of type <CODE>bool</CODE>, called \p name
  and with value \p value.

  \ingroup PPL_CXX_interface
  Differently from static constants, \p name needs not (and cannot) be
  defined (for static constants, the need for a further definition is
  mandated by Section 9.4.2/4 of the C++ standard).
*/
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
#define const_bool_nodef(name, value)		\
  enum { name = (value) }

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \brief
  Declares a per-class constant of type <CODE>int</CODE>, called \p name
  and with value \p value.

  \ingroup PPL_CXX_interface
  Differently from static constants, \p name needs not (and cannot) be
  defined (for static constants, the need for a further definition is
  mandated by Section 9.4.2/4 of the C++ standard).
*/
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
#define const_int_nodef(name, value) \
  enum { name = (value) }

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \brief
  Declares a per-class constant of type \p type, called \p name
  and with value \p value.  The value of the constant is accessible
  by means of the syntax <CODE>name()</CODE>.

  \ingroup PPL_CXX_interface
  Differently from static constants, \p name needs not (and cannot) be
  defined (for static constants, the need for a further definition is
  mandated by Section 9.4.2/4 of the C++ standard).
*/
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
#define const_value_nodef(type, name, value)	\
  static type name() {				\
    return value;				\
  }

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \brief
  Declares a per-class constant of type \p type, called \p name
  and with value \p value.  A constant reference to the constant
  is accessible by means of the syntax <CODE>name()</CODE>.

  \ingroup PPL_CXX_interface
  Differently from static constants, \p name needs not (and cannot) be
  defined (for static constants, the need for a further definition is
  mandated by Section 9.4.2/4 of the C++ standard).
*/
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
#define const_ref_nodef(type, name, value)				\
  static const type& name() {						\
    static type name(value);						\
    return name;							\
  }

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \brief
  A class that is only defined if \p b evaluates to <CODE>true</CODE>.

  \ingroup PPL_CXX_interface
  This is the non-specialized case, so the class is declared but not defined.
*/
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <bool b>
struct Compile_Time_Check;

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \brief
  A class that is only defined if \p b evaluates to <CODE>true</CODE>.

  \ingroup PPL_CXX_interface
  This is the specialized case with \p b equal to <CODE>true</CODE>,
  so the class is declared and (trivially) defined.
*/
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <>
struct Compile_Time_Check<true> {
};

#define PPL_COMPILE_TIME_CHECK_NAME(suffix) compile_time_check_ ## suffix
#define PPL_COMPILE_TIME_CHECK_AUX(e, suffix)				\
  enum {								\
    /* If e evaluates to false, then the sizeof cannot be compiled. */  \
    PPL_COMPILE_TIME_CHECK_NAME(suffix)					\
    = sizeof(Parma_Polyhedra_Library::					\
	     Compile_Time_Check<static_cast<bool>(e)>)			\
  }

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \brief
  Produces a compilation error if the compile-time constant \p e does
  not evaluate to <CODE>true</CODE>
  \ingroup PPL_CXX_interface
*/
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
#define PPL_COMPILE_TIME_CHECK(e, msg) PPL_COMPILE_TIME_CHECK_AUX(e, __LINE__)

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \brief
  A class holding a constant called <CODE>value</CODE> that evaluates
  to \p b.
  \ingroup PPL_CXX_interface
*/
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <bool b>
struct Bool {
  enum {
    value = b
  };
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \brief
  A class holding a constant called <CODE>value</CODE> that evaluates
  to <CODE>true</CODE>.
  \ingroup PPL_CXX_interface
*/
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
struct True : public Bool<true> {
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \brief
  A class holding a constant called <CODE>value</CODE> that evaluates
  to <CODE>false</CODE>.
  \ingroup PPL_CXX_interface
*/
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
struct False : public Bool<false> {
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \brief
  A class holding a constant called <CODE>value</CODE> that evaluates
  to <CODE>true</CODE> if and only if \p T1 is the same type as \p T2.

  \ingroup PPL_CXX_interface
  This is the non-specialized case, in which \p T1 and \p T2 can be different.
*/
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename T1, typename T2>
struct Is_Same : public False {
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \brief
  A class holding a constant called <CODE>value</CODE> that evaluates
  to <CODE>true</CODE> if and only if \p T1 is the same type as \p T2.

  \ingroup PPL_CXX_interface
  This is the specialization in which \p T1 and \p T2 are equal.
*/
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename T>
struct Is_Same<T, T> : public True {
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \brief
  A class holding a constant called <CODE>value</CODE> that evaluates
  to <CODE>true</CODE> if and only if \p Base is the same type as \p Derived
  or \p Derived is a class derived from \p Base.

  \ingroup PPL_CXX_interface
  \note
  Care must be taken to use this predicate with template classes.
  Suppose we have
  \code
  template <typename T> struct B;
  template <typename T> struct D : public B<T>;
  \endcode
  Of course, we cannot test if, for some type variable <CODE>U</CODE>,
  we have <CODE>Is_Same_Or_Derived<B<U>, Type>::value == true</CODE>.
  But we can do as follows:
  \code
  struct B_Base {
  };

  template <typename T> struct B : public B_Base;
  \endcode
  This enables us to enquire
  <CODE>Is_Same_Or_Derived<B_Base, Type>::value</CODE>.
*/
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename Base, typename Derived>
struct Is_Same_Or_Derived {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  //! A class that is constructible from just anything.
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
  struct Any {
    //! The universal constructor.
    template <typename T>
    Any(const T&);
  };

  //! Overloading with \p Base.
  static char func(const Base&);

  //! Overloading with \p Any.
  static double func(Any);

  //! A function obtaining a const reference to a \p Derived object.
  static const Derived& derived_object();

  PPL_COMPILE_TIME_CHECK(sizeof(char) != sizeof(double),
                         "architecture with sizeof(char) == sizeof(double)"
                         " (!?)");

  enum {
    /*!
      Assuming <CODE>sizeof(char) != sizeof(double)</CODE>, the C++
      overload resolution mechanism guarantees that \p value evaluates
      to <CODE>true</CODE> if and only if \p Base is the same type
      as \p Derived or \p Derived is a class derived from \p Base.
    */
    value = (sizeof(func(derived_object())) == sizeof(char))
  };
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \brief
  A class that provides a type member called <CODE>type</CODE> equivalent
  to \p T if and only if \p b is <CODE>true</CODE>.

  \ingroup PPL_CXX_interface
  This is the non-specialized case, in which the <CODE>type</CODE> member
  is not present.
*/
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <bool b, typename T = void>
struct Enable_If {
};

template <typename Type, Type, typename T = void>
struct Enable_If_Is {
  typedef T type;
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \brief
  A class that provides a type member called <CODE>type</CODE> equivalent
  to \p T if and only if \p b is <CODE>true</CODE>.

  \ingroup PPL_CXX_interface
  This is the specialization in which the <CODE>type</CODE> member
  is present.

  \note
  Let <CODE>T</CODE>, <CODE>T1</CODE> and <CODE>T2</CODE> be any type
  expressions and suppose we have some template function
  <CODE>T f(T1, T2)</CODE>.  If we want to declare a specialization
  that is enabled only if some compile-time checkable condition holds,
  we simply declare the specialization by
  \code
  template ...
  typename Enable_If<condition, T>::type
  foo(T1 x, T2 y);
  \endcode
  For all the instantiations of the template parameters that cause
  <CODE>condition</CODE> to evaluate to <CODE>false</CODE>,
  the <CODE>Enable_If<condition, T>::type</CODE> member will not be defined.
  Hence, for that instantiations, the specialization will not be eligible.
*/
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename T>
struct Enable_If<true, T> {
  typedef T type;
};

template <typename T>
struct Is_Native : public False {
};

template <> struct Is_Native<signed char> : public True { };
template <> struct Is_Native<signed short> : public True { };
template <> struct Is_Native<signed int> : public True { };
template <> struct Is_Native<signed long> : public True { };
template <> struct Is_Native<signed long long> : public True { };
template <> struct Is_Native<unsigned char> : public True { };
template <> struct Is_Native<unsigned short> : public True { };
template <> struct Is_Native<unsigned int> : public True { };
template <> struct Is_Native<unsigned long> : public True { };
template <> struct Is_Native<unsigned long long> : public True { };

#if PPL_SUPPORTED_FLOAT
template <> struct Is_Native<float> : public True { };
#endif
#if PPL_SUPPORTED_DOUBLE
template <> struct Is_Native<double> : public True { };
#endif
#if PPL_SUPPORTED_LONG_DOUBLE
template <> struct Is_Native<long double> : public True { };
#endif

template <> struct Is_Native<mpz_class> : public True { };

template <> struct Is_Native<mpq_class> : public True { };

} // namespace Parma_Polyhedra_Library

/* Automatically generated from PPL source file ../src/Slow_Copy.hh line 1. */
/* Basic Slow_Copy classes declarations.
*/


/* Automatically generated from PPL source file ../src/Slow_Copy.hh line 27. */
#include <gmpxx.h>

namespace Parma_Polyhedra_Library {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \ingroup PPL_CXX_interface
  Copies are not slow by default.
*/
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename T>
struct Slow_Copy : public False {
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \ingroup PPL_CXX_interface
  Copies are slow for mpz_class objects.
*/
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <>
struct Slow_Copy<mpz_class> : public True {
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \ingroup PPL_CXX_interface
  Copies are slow for mpq_class objects.
*/
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <>
struct Slow_Copy<mpq_class> : public True {
};

} // namespace Parma_Polyhedra_Library

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

namespace Parma_Polyhedra_Library {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! A pool of temporary items of type \p T.
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename T>
class Temp_Item {
public:
  //! Obtains a refeence to a temporary item.
  static Temp_Item& obtain();

  //! Releases the temporary item \p p.
  static void release(Temp_Item& p);

  //! Returns a reference to the encapsulated item.
  T& item();

private:
  //! The encapsulated item.
  T item_;

  //! Pointer to the next item in the free list.
  Temp_Item* next;

  //! Head of the free list.
  static Temp_Item* free_list_head;

  //! Default constructor.
  Temp_Item();

  //! Copy constructor: private and intentionally not implemented.
  Temp_Item(const Temp_Item&);

  //! Assignment operator: private and intentionally not implemented.
  Temp_Item& operator=(const Temp_Item&);
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! An holder for a reference to a temporary object.
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename T>
class Temp_Reference_Holder {
public:
  //! Constructs an holder holding \p p.
  Temp_Reference_Holder(Temp_Item<T>& p);

  //! Destructor.
  ~Temp_Reference_Holder();

  //! Returns a reference to the held item.
  T& item();

private:
  //! The held item, encapsulated.
  Temp_Item<T>& held;
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! An (fake) holder for the value of a temporary object.
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename T>
class Temp_Value_Holder {
public:
  //! Constructs a fake holder.
  Temp_Value_Holder();

  //! Returns the value of the held item.
  T item();

private:
  //! The held item.
  T item_;
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! A structure for handling temporaries with a global free list.
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename T>
struct Temp_From_Free_List {
  //! The type of the temporaries.
  typedef T& type;

  //! The type of the holder.
  typedef Temp_Reference_Holder<T> holder_type;

  //! Obtain the holder for a new temporary.
  static holder_type obtain_holder();
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! A structure for handling temporaries with local variables.
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename T>
struct Temp_From_Local_Variable {
  //! The type of the temporaries.
  typedef T type;

  //! The type of the holder.
  typedef Temp_Value_Holder<T> holder_type;

  //! Obtain the holder for a new temporary.
  static holder_type obtain_holder();
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! A structure for the efficient handling of temporaries.
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename T, typename Enable = void>
class Dirty_Temp;

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Specialization for the handling of temporaries with a free list.
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename T>
class Dirty_Temp<T, typename Enable_If<Slow_Copy<T>::value>::type>
  : public Temp_From_Free_List<T> {
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Specialization for the handling of temporaries with local variables.
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename T>
class Dirty_Temp<T, typename Enable_If<!Slow_Copy<T>::value>::type>
  : public Temp_From_Local_Variable<T> {
};

} // namespace Parma_Polyhedra_Library

/* Automatically generated from PPL source file ../src/Temp.inlines.hh line 1. */
/* Temp_* classes implementation: inline functions.
*/


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

namespace Parma_Polyhedra_Library {

template <typename T>
inline
Temp_Item<T>::Temp_Item()
  : item_() {
}

template <typename T>
inline T&
Temp_Item<T>::item() {
    return item_;
}

template <typename T>
inline Temp_Item<T>&
Temp_Item<T>::obtain() {
  if (free_list_head != 0) {
    Temp_Item* p = free_list_head;
    free_list_head = free_list_head->next;
    return *p;
  }
  else
    return *new Temp_Item();
}

template <typename T>
inline void
Temp_Item<T>::release(Temp_Item& p) {
  p.next = free_list_head;
  free_list_head = &p;
}

template <typename T>
inline
Temp_Reference_Holder<T>::Temp_Reference_Holder(Temp_Item<T>& p)
  : held(p) {
}

template <typename T>
inline
Temp_Reference_Holder<T>::~Temp_Reference_Holder() {
  Temp_Item<T>::release(held);
}

template <typename T>
inline T&
Temp_Reference_Holder<T>::item() {
  return held.item();
}

template <typename T>
inline
Temp_Value_Holder<T>::Temp_Value_Holder() {
}

template <typename T>
inline T
Temp_Value_Holder<T>::item() {
  return item_;
}

template <typename T>
inline typename Temp_From_Free_List<T>::holder_type
Temp_From_Free_List<T>::obtain_holder() {
  return Temp_Reference_Holder<T>(Temp_Item<T>::obtain());
}

template <typename T>
inline typename Temp_From_Local_Variable<T>::holder_type
Temp_From_Local_Variable<T>::obtain_holder() {
  return Temp_Value_Holder<T>();
}

} // namespace Parma_Polyhedra_Library

#define PPL_DIRTY_TEMP(T, id)						\
  typename Parma_Polyhedra_Library::Dirty_Temp<T>::holder_type holder ## id = \
    Parma_Polyhedra_Library::Dirty_Temp<T>::obtain_holder();		\
  typename Parma_Polyhedra_Library::Dirty_Temp<T>::type id =		\
    holder ## id.item()

#define PPL_DIRTY_TEMP0(T, id)						\
  Parma_Polyhedra_Library::Dirty_Temp<T>::holder_type holder ## id =	\
    Parma_Polyhedra_Library::Dirty_Temp<T>::obtain_holder();		\
  Parma_Polyhedra_Library::Dirty_Temp<T>::type id = holder ## id.item()

/* Automatically generated from PPL source file ../src/Temp.templates.hh line 1. */
/* Temp_* classes implementation: non-inline template members.
*/


namespace Parma_Polyhedra_Library {

template <typename T>
Temp_Item<T>* Temp_Item<T>::free_list_head = 0;

} // namespace Parma_Polyhedra_Library

/* Automatically generated from PPL source file ../src/Temp.defs.hh line 159. */

/* 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/Float.defs.hh line 1. */
/* IEC 559 floating point format related functions.
*/


/* Automatically generated from PPL source file ../src/Float.defs.hh line 28. */
#include <gmp.h>
#include <cassert>
#include <cmath>

#ifdef NAN
#define PPL_NAN NAN
#else
#define PPL_NAN (HUGE_VAL - HUGE_VAL)
#endif

namespace Parma_Polyhedra_Library {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \ingroup PPL_CXX_interface */
#endif // defined(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 WORDS_BIGENDIAN
#ifndef PPL_WORDS_BIGENDIAN
#define PPL_WORDS_BIGENDIAN
#endif
#endif

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \ingroup PPL_CXX_interface */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)

struct float_ieee754_double {
#ifdef PPL_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 // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)

struct float_intel_double_extended {
#ifdef PPL_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 // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)

struct float_ieee754_quad {
#ifdef PPL_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 // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename T>
class Float : public False { };

#if PPL_SUPPORTED_FLOAT
template <>
class Float<float> : public True {
public:
#if PPL_CXX_FLOAT_BINARY_FORMAT == PPL_FLOAT_IEEE754_SINGLE
  typedef float_ieee754_single Binary;
#elif PPL_CXX_FLOAT_BINARY_FORMAT == PPL_FLOAT_IEEE754_DOUBLE
  typedef float_ieee754_double Binary;
#elif PPL_CXX_FLOAT_BINARY_FORMAT == PPL_FLOAT_IEEE754_QUAD
  typedef float_ieee754_quad Binary;
#elif PPL_CXX_FLOAT_BINARY_FORMAT == PPL_FLOAT_INTEL_DOUBLE_EXTENDED
  typedef float_intel_double_extended Binary;
#else
#error "invalid value for PPL_CXX_FLOAT_BINARY_FORMAT"
#endif
  union {
    float number;
    Binary binary;
  } u;
  Float();
  Float(float v);
  float value();
};
#endif

#if PPL_SUPPORTED_DOUBLE
template <>
class Float<double> : public True {
public:
#if PPL_CXX_DOUBLE_BINARY_FORMAT == PPL_FLOAT_IEEE754_SINGLE
  typedef float_ieee754_single Binary;
#elif PPL_CXX_DOUBLE_BINARY_FORMAT == PPL_FLOAT_IEEE754_DOUBLE
  typedef float_ieee754_double Binary;
#elif PPL_CXX_DOUBLE_BINARY_FORMAT == PPL_FLOAT_IEEE754_QUAD
  typedef float_ieee754_quad Binary;
#elif PPL_CXX_DOUBLE_BINARY_FORMAT == PPL_FLOAT_INTEL_DOUBLE_EXTENDED
  typedef float_intel_double_extended Binary;
#else
#error "invalid value for PPL_CXX_DOUBLE_BINARY_FORMAT"
#endif
  union {
    double number;
    Binary binary;
  } u;
  Float();
  Float(double v);
  double value();
};
#endif

#if PPL_SUPPORTED_LONG_DOUBLE
template <>
class Float<long double> : public True {
public:
#if PPL_CXX_LONG_DOUBLE_BINARY_FORMAT == PPL_FLOAT_IEEE754_SINGLE
  typedef float_ieee754_single Binary;
#elif PPL_CXX_LONG_DOUBLE_BINARY_FORMAT == PPL_FLOAT_IEEE754_DOUBLE
  typedef float_ieee754_double Binary;
#elif PPL_CXX_LONG_DOUBLE_BINARY_FORMAT == PPL_FLOAT_IEEE754_QUAD
  typedef float_ieee754_quad Binary;
#elif PPL_CXX_LONG_DOUBLE_BINARY_FORMAT == PPL_FLOAT_INTEL_DOUBLE_EXTENDED
  typedef float_intel_double_extended Binary;
#else
#error "invalid value for PPL_CXX_LONG_DOUBLE_BINARY_FORMAT"
#endif
  union {
    long double number;
    Binary binary;
  } u;
  Float();
  Float(long double v);
  long double value();
};
#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>

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);
}

#if PPL_SUPPORTED_FLOAT
inline
Float<float>::Float() {
}

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

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

#if PPL_SUPPORTED_DOUBLE
inline
Float<double>::Float() {
}

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

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

#if PPL_SUPPORTED_LONG_DOUBLE
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 275. */

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

namespace Parma_Polyhedra_Library {

namespace Checked {


// 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 PPL_FUNCTION_CLASS(name) name ## _function_struct

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

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

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

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

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

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

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

#define PPL_DECLARE_FUN2_0_0(name, ret_type, qual1, type1, qual2, type2) \
  template <typename Policy1, typename Policy2,                         \
            typename type1, typename type2>                             \
  struct PPL_FUNCTION_CLASS(name);                                      \
  template <typename Policy1, typename Policy2,                         \
            typename type1, typename type2>                             \
  inline ret_type name(qual1 type1& arg1, qual2 type2& arg2) {          \
    return PPL_FUNCTION_CLASS(name)<Policy1, Policy2,                   \
      type1, type2>::function(arg1, arg2);                              \
  }

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

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

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

#define PPL_DECLARE_FUN5_0_1(name, ret_type,				\
                             qual1, type1, qual2, type2, qual3, type3,	\
                             qual4, type4, qual5, type5,                \
                             after1)					\
  template <typename Policy1, typename Policy2, typename Policy3,       \
            typename Policy4,typename Policy5,				\
            typename type1, typename type2, typename type3,		\
            typename type4, typename type5>				\
  struct PPL_FUNCTION_CLASS(name);                                      \
  template <typename Policy1, typename Policy2, typename Policy3,       \
            typename Policy4,typename Policy5,				\
            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 PPL_FUNCTION_CLASS(name)<Policy1, Policy2, Policy3,          \
      Policy4, Policy5, type1, type2, type3, type4, type5>              \
      ::function(arg1, arg2, arg3, arg4, arg5, a1);			\
  }

#define PPL_SPECIALIZE_FUN1_0_0(name, func, ret_type, qual, type)       \
  template <typename Policy>                                            \
  struct PPL_FUNCTION_CLASS(name)<Policy, type> {                       \
    static inline ret_type function(qual type& arg) {                   \
      return func<Policy>(arg);                                         \
    }                                                                   \
  };

#define PPL_SPECIALIZE_FUN1_0_1(name, func, ret_type, qual, type, after1) \
  template <typename Policy>                                            \
  struct PPL_FUNCTION_CLASS(name)<Policy, type> {                       \
    static inline ret_type function(qual type& arg, after1 a1) {        \
      return func<Policy>(arg, a1);                                     \
    }                                                                   \
  };

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

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

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

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

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

#define PPL_SPECIALIZE_FUN2_0_0(name, func, ret_type, qual1, type1,     \
                                qual2, type2)                           \
  template <typename Policy1, typename Policy2>				\
  struct PPL_FUNCTION_CLASS(name)<Policy1, Policy2, type1, type2> {     \
    static inline ret_type function(qual1 type1& arg1,                  \
                                    qual2 type2 &arg2) {                \
      return func<Policy1, Policy2>(arg1, arg2);                        \
    }                                                                   \
  };

#define PPL_SPECIALIZE_FUN2_0_1(name, func, ret_type, qual1, type1,     \
                                qual2, type2, after1)                   \
  template <typename Policy1, typename Policy2>                         \
  struct PPL_FUNCTION_CLASS(name)<Policy1, Policy2, type1, type2> {     \
    static inline ret_type function(qual1 type1& arg1,                  \
                                    qual2 type2 &arg2, after1 a1) {     \
      return func<Policy1, Policy2>(arg1, arg2, a1);                    \
    }                                                                   \
  };

#define PPL_SPECIALIZE_FUN2_0_2(name, func, ret_type, qual1, type1,     \
                                qual2, type2, after1, after2)           \
  template <typename Policy1, typename Policy2>                         \
 struct PPL_FUNCTION_CLASS(name)<Policy1, Policy2, type1, type2> {      \
    static inline ret_type function(qual1 type1& arg1,                  \
                                    qual2 type2 &arg2,                  \
                                    after1 a1, after2 a2) {             \
      return func<Policy1, Policy2>(arg1, arg2, a1, a2);                \
    }                                                                   \
  };

#define PPL_SPECIALIZE_FUN3_0_1(name, func, ret_type, qual1, type1,     \
                                qual2, type2, qual3, type3, after1)     \
  template <typename Policy1, typename Policy2, typename Policy3>       \
  struct PPL_FUNCTION_CLASS(name) <Policy1, Policy2, Policy3,           \
                                   type1, type2, type3> {               \
    static inline Result function(qual1 type1& arg1, qual2 type2 &arg2, \
                                  qual3 type3 &arg3, after1 a1) {       \
      return func<Policy1, Policy2, Policy3>(arg1, arg2, arg3, a1);     \
    }                                                                   \
  };

#define PPL_SPECIALIZE_FUN5_0_1(name, func, ret_type,                   \
                                qual1, type1, qual2, type2,             \
                                qual3, type3,                           \
                                qual4, type4, qual5, type5, after1)     \
  template <typename Policy1, typename Policy2, typename Policy3,	\
	    typename Policy4, typename Policy5>				\
  struct PPL_FUNCTION_CLASS(name) <Policy1, Policy2, Policy3, Policy4,  \
                                   Policy5,                             \
                                   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 func<Policy1, Policy2, Policy3, Policy4, Policy5>(arg1,    \
                                                               arg2,    \
                                                               arg3,    \
                                                               arg4,    \
                                                               arg5,    \
                                                               a1);     \
    }									\
};

// The `nonconst' macro helps readability of the sequel.
#ifdef nonconst
#define PPL_SAVED_nonconst nonconst
#undef nonconst
#endif
#define nonconst

#define PPL_SPECIALIZE_COPY(func, Type)                                 \
  PPL_SPECIALIZE_FUN2_0_0(copy, func, void, nonconst, Type, const, Type)
#define PPL_SPECIALIZE_SGN(func, From)                          \
  PPL_SPECIALIZE_FUN1_0_0(sgn, func, Result, const, From)
#define PPL_SPECIALIZE_CMP(func, Type1, Type2)                          \
  PPL_SPECIALIZE_FUN2_0_0(cmp, func, Result, const, Type1, const, Type2)
#define PPL_SPECIALIZE_CLASSIFY(func, Type)                             \
  PPL_SPECIALIZE_FUN1_0_3(classify, func, Result, const, Type, bool, bool, bool)
#define PPL_SPECIALIZE_IS_NAN(func, Type)                       \
  PPL_SPECIALIZE_FUN1_0_0(is_nan, func, bool, const, Type)
#define PPL_SPECIALIZE_IS_MINF(func, Type)                      \
  PPL_SPECIALIZE_FUN1_0_0(is_minf, func, bool, const, Type)
#define PPL_SPECIALIZE_IS_PINF(func, Type)                      \
  PPL_SPECIALIZE_FUN1_0_0(is_pinf, func, bool, const, Type)
#define PPL_SPECIALIZE_IS_INT(func, Type)                       \
  PPL_SPECIALIZE_FUN1_0_0(is_int, func, bool, const, Type)
#define PPL_SPECIALIZE_ASSIGN_SPECIAL(func, Type)                       \
  PPL_SPECIALIZE_FUN1_0_2(assign_special, func, Result,                 \
                          nonconst, Type, Result, Rounding_Dir)
#define PPL_SPECIALIZE_CONSTRUCT_SPECIAL(func, Type)                    \
  PPL_SPECIALIZE_FUN1_0_2(construct_special, func, Result, nonconst,    \
                          Type, Result, Rounding_Dir)
#define PPL_SPECIALIZE_CONSTRUCT(func, To, From)                        \
  PPL_SPECIALIZE_FUN2_0_1(construct, func, Result, nonconst, To, \
                          const, From, Rounding_Dir)
#define PPL_SPECIALIZE_ASSIGN(func, To, From)                           \
  PPL_SPECIALIZE_FUN2_0_1(assign, func, Result, nonconst, To,           \
                          const, From, Rounding_Dir)
#define PPL_SPECIALIZE_FLOOR(func, To, From)                            \
  PPL_SPECIALIZE_FUN2_0_1(floor, func, Result, nonconst, To,            \
                          const, From, Rounding_Dir)
#define PPL_SPECIALIZE_CEIL(func, To, From)                             \
  PPL_SPECIALIZE_FUN2_0_1(ceil, func, Result, nonconst, To, \
                          const, From, Rounding_Dir)
#define PPL_SPECIALIZE_TRUNC(func, To, From)                            \
  PPL_SPECIALIZE_FUN2_0_1(trunc, func, Result, nonconst, To,            \
                          const, From, Rounding_Dir)
#define PPL_SPECIALIZE_NEG(func, To, From)                              \
  PPL_SPECIALIZE_FUN2_0_1(neg, func, Result, nonconst, To,              \
                          const, From, Rounding_Dir)
#define PPL_SPECIALIZE_ABS(func, To, From)                              \
  PPL_SPECIALIZE_FUN2_0_1(abs, func, Result, nonconst, To,              \
                          const, From, Rounding_Dir)
#define PPL_SPECIALIZE_SQRT(func, To, From)                             \
  PPL_SPECIALIZE_FUN2_0_1(sqrt, func, Result, nonconst, To,             \
                          const, From, Rounding_Dir)
#define PPL_SPECIALIZE_ADD(func, To, From1, From2)                      \
  PPL_SPECIALIZE_FUN3_0_1(add, func, Result, nonconst, To,              \
                          const, From1, const, From2, Rounding_Dir)
#define PPL_SPECIALIZE_SUB(func, To, From1, From2)                      \
  PPL_SPECIALIZE_FUN3_0_1(sub, func, Result, nonconst, To,              \
                          const, From1, const, From2, Rounding_Dir)
#define PPL_SPECIALIZE_MUL(func, To, From1, From2)                      \
  PPL_SPECIALIZE_FUN3_0_1(mul, func, Result, nonconst, To,              \
                          const, From1, const, From2, Rounding_Dir)
#define PPL_SPECIALIZE_DIV(func, To, From1, From2)                      \
  PPL_SPECIALIZE_FUN3_0_1(div, func, Result, nonconst, To,              \
                          const, From1, const, From2, Rounding_Dir)
#define PPL_SPECIALIZE_REM(func, To, From1, From2)                      \
  PPL_SPECIALIZE_FUN3_0_1(rem, func, Result, nonconst, To,              \
                          const, From1, const, From2, Rounding_Dir)
#define PPL_SPECIALIZE_IDIV(func, To, From1, From2)                     \
  PPL_SPECIALIZE_FUN3_0_1(idiv, func, Result, nonconst, To,             \
                          const, From1, const, From2, Rounding_Dir)
#define PPL_SPECIALIZE_MUL2EXP(func, To, From)                          \
  PPL_SPECIALIZE_FUN2_0_2(mul2exp, func, Result, nonconst, To,          \
                          const, From, int, Rounding_Dir)
#define PPL_SPECIALIZE_DIV2EXP(func, To, From)                          \
  PPL_SPECIALIZE_FUN2_0_2(div2exp, func, Result, nonconst, To,          \
                          const, From, int, Rounding_Dir)
#define PPL_SPECIALIZE_ADD_MUL(func, To, From1, From2)                  \
  PPL_SPECIALIZE_FUN3_0_1(add_mul, func, Result, nonconst, To,          \
                          const, From1, const, From2, Rounding_Dir)
#define PPL_SPECIALIZE_SUB_MUL(func, To, From1, From2)                  \
  PPL_SPECIALIZE_FUN3_0_1(sub_mul, func, Result, nonconst, To,          \
                          const, From1, const, From2, Rounding_Dir)
#define PPL_SPECIALIZE_GCD(func, To, From1, From2)                      \
  PPL_SPECIALIZE_FUN3_0_1(gcd, func, Result, nonconst, To,              \
                          const, From1, const, From2, Rounding_Dir)
#define PPL_SPECIALIZE_GCDEXT(func, To1, From1, From2, To2, To3)        \
  PPL_SPECIALIZE_FUN5_0_1(gcdext, func, Result, nonconst, To1,		\
                          nonconst, To2, nonconst, To3,                 \
                          const, From1, const, From2, Rounding_Dir)
#define PPL_SPECIALIZE_LCM(func, To, From1, From2)                      \
  PPL_SPECIALIZE_FUN3_0_1(lcm, func, Result, nonconst, To,              \
                          const, From1, const, From2, Rounding_Dir)
#define PPL_SPECIALIZE_INPUT(func, Type)                                \
  PPL_SPECIALIZE_FUN1_0_2(input, func, Result, nonconst, Type,          \
                          std::istream&, Rounding_Dir)
#define PPL_SPECIALIZE_OUTPUT(func, Type)                               \
  PPL_SPECIALIZE_FUN1_1_2(output, func, Result, std::ostream&,          \
                          const, Type,                                  \
                          const Numeric_Format&, Rounding_Dir)


PPL_DECLARE_FUN2_0_0(copy,
                     void, nonconst, Type1, const, Type2)
PPL_DECLARE_FUN1_0_0(sgn,
                     Result, const, From)
PPL_DECLARE_FUN2_0_0(cmp,
                     Result, const, Type1, const, Type2)
PPL_DECLARE_FUN1_0_3(classify,
                     Result, const, Type, bool, bool, bool)
PPL_DECLARE_FUN1_0_0(is_nan,
                     bool, const, Type)
PPL_DECLARE_FUN1_0_0(is_minf,
                     bool, const, Type)
PPL_DECLARE_FUN1_0_0(is_pinf,
                     bool, const, Type)
PPL_DECLARE_FUN1_0_0(is_int,
                     bool, const, Type)
PPL_DECLARE_FUN1_0_2(assign_special,
                     Result, nonconst, Type, Result, Rounding_Dir)
PPL_DECLARE_FUN1_0_2(construct_special,
                     Result, nonconst, Type, Result, Rounding_Dir)
PPL_DECLARE_FUN2_0_1(construct,
                     Result, nonconst, To, const, From, Rounding_Dir)
PPL_DECLARE_FUN2_0_1(assign,
                     Result, nonconst, To, const, From, Rounding_Dir)
PPL_DECLARE_FUN2_0_1(floor,
                     Result, nonconst, To, const, From, Rounding_Dir)
PPL_DECLARE_FUN2_0_1(ceil,
                     Result, nonconst, To, const, From, Rounding_Dir)
PPL_DECLARE_FUN2_0_1(trunc,
                     Result, nonconst, To, const, From, Rounding_Dir)
PPL_DECLARE_FUN2_0_1(neg,
                     Result, nonconst, To, const, From, Rounding_Dir)
PPL_DECLARE_FUN2_0_1(abs,
                     Result, nonconst, To, const, From, Rounding_Dir)
PPL_DECLARE_FUN2_0_1(sqrt,
                     Result, nonconst, To, const, From, Rounding_Dir)
PPL_DECLARE_FUN3_0_1(add,
                     Result, nonconst, To,
                     const, From1, const, From2, Rounding_Dir)
PPL_DECLARE_FUN3_0_1(sub,
                     Result, nonconst, To,
                     const, From1, const, From2, Rounding_Dir)
PPL_DECLARE_FUN3_0_1(mul,
                     Result, nonconst, To,
                     const, From1, const, From2, Rounding_Dir)
PPL_DECLARE_FUN3_0_1(div,
                     Result, nonconst, To,
                     const, From1, const, From2, Rounding_Dir)
PPL_DECLARE_FUN3_0_1(rem,
                     Result, nonconst, To,
                     const, From1, const, From2, Rounding_Dir)
PPL_DECLARE_FUN3_0_1(idiv,
                     Result, nonconst, To,
                     const, From1, const, From2, Rounding_Dir)
PPL_DECLARE_FUN2_0_2(mul2exp,
                     Result, nonconst, To, const, From, int, Rounding_Dir)
PPL_DECLARE_FUN2_0_2(div2exp,
                     Result, nonconst, To, const, From, int, Rounding_Dir)
PPL_DECLARE_FUN3_0_1(add_mul,
                     Result, nonconst, To,
                     const, From1, const, From2, Rounding_Dir)
PPL_DECLARE_FUN3_0_1(sub_mul,
                     Result, nonconst, To,
                     const, From1, const, From2, Rounding_Dir)
PPL_DECLARE_FUN3_0_1(gcd,
                     Result, nonconst, To,
                     const, From1, const, From2, Rounding_Dir)
PPL_DECLARE_FUN5_0_1(gcdext,
                     Result, nonconst, To1, nonconst, To2, nonconst, To3,
                     const, From1, const, From2, Rounding_Dir)
PPL_DECLARE_FUN3_0_1(lcm,
                     Result, nonconst, To,
                     const, From1, const, From2, Rounding_Dir)
PPL_DECLARE_FUN1_0_2(input,
                     Result, nonconst, Type, std::istream&, Rounding_Dir)
PPL_DECLARE_FUN1_1_2(output,
                     Result, std::ostream&, const, Type,
                     const Numeric_Format&, Rounding_Dir)

#undef PPL_DECLARE_FUN1_0_0
#undef PPL_DECLARE_FUN1_0_1
#undef PPL_DECLARE_FUN1_0_2
#undef PPL_DECLARE_FUN1_0_3
#undef PPL_DECLARE_FUN1_1_1
#undef PPL_DECLARE_FUN1_1_2
#undef PPL_DECLARE_FUN1_2_2
#undef PPL_DECLARE_FUN2_0_0
#undef PPL_DECLARE_FUN2_0_1
#undef PPL_DECLARE_FUN2_0_2
#undef PPL_DECLARE_FUN3_0_1
#undef PPL_DECLARE_FUN5_0_1

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 {
  static const Result code = VC_MINUS_INFINITY;
};
struct Plus_Infinity {
  static const Result code = VC_PLUS_INFINITY;
};
struct Not_A_Number {
  static const Result code = VC_NAN;
};

template <typename T>
struct Is_Special : public False { };

template <>
struct Is_Special<Minus_Infinity> : public True {};

template <>
struct Is_Special<Plus_Infinity> : public True {};

template <>
struct Is_Special<Not_A_Number> : public True {};


#define MINUS_INFINITY Minus_Infinity()
#define PLUS_INFINITY Plus_Infinity()
#define NOT_A_NUMBER Not_A_Number()

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \ingroup PPL_CXX_interface */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename T>
struct Checked_Number_Transparent_Policy {
  //! Checks for overflowed result.
  const_bool_nodef(check_overflow, false);

  //! Checks for attempts to add infinities with different sign.
  const_bool_nodef(check_inf_add_inf, false);

  //! Checks for attempts to subtract infinities with same sign.
  const_bool_nodef(check_inf_sub_inf, false);

  //! Checks for attempts to multiply infinities by zero.
  const_bool_nodef(check_inf_mul_zero, false);

  //! Checks for attempts to divide by zero.
  const_bool_nodef(check_div_zero, false);

  //! Checks for attempts to divide infinities.
  const_bool_nodef(check_inf_div_inf, false);

  //! Checks for attempts to compute remainder of infinities.
  const_bool_nodef(check_inf_mod, false);

  //! Checks for attempts to take the square root of a negative number.
  const_bool_nodef(check_sqrt_neg, false);

  //! Handles not-a-number special value.
  const_bool_nodef(has_nan, std::numeric_limits<T>::has_quiet_NaN);

  //! Handles infinity special values.
  const_bool_nodef(has_infinity, std::numeric_limits<T>::has_infinity);

  //! Representation is identical to primitive.
  const_bool_nodef(convertible, true);

  //! When true, requests to check for FPU inexact result are honored.
  const_bool_nodef(fpu_check_inexact, false);

  //! Return VC_NAN on NaN result also for native extended.
  const_bool_nodef(check_nan_result, false);
  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);
};

} // 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_OR_EQUAL,
  //! Equal to.
  EQUAL,
  //! Greater than or equal to.
  GREATER_OR_EQUAL,
  //! Greater than.
  GREATER_THAN,
  //! Not equal to.
  NOT_EQUAL
};

//! 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/C_Integer.hh line 1. */
/* C integers info.
*/


/* Automatically generated from PPL source file ../src/C_Integer.hh line 27. */
#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 PPL_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 PPL_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 PPL_SIZEOF_LONG_LONG == 8
#define ULLONG_MAX 0xffffffffffffffffULL
#endif
#endif

namespace Parma_Polyhedra_Library {

template <typename T>
struct C_Integer : public False { };

template <>
struct C_Integer<signed char> : public True {
  enum { is_signed = true };
  typedef void smaller_type;
  typedef void smaller_signed_type;
  typedef void smaller_unsigned_type;
  typedef unsigned char other_type;
  static const signed char min = SCHAR_MIN;
  static const signed char max = SCHAR_MAX;
};

template <>
struct C_Integer<signed short> : public True {
  enum { is_signed = true };
  typedef signed char smaller_type;
  typedef signed char smaller_signed_type;
  typedef unsigned char smaller_unsigned_type;
  typedef unsigned short other_type;
  static const signed short min = SHRT_MIN;
  static const signed short max = SHRT_MAX;
};

template <>
struct C_Integer<signed int> : public True {
  enum { is_signed = true };
  typedef signed short smaller_type;
  typedef signed short smaller_signed_type;
  typedef unsigned short smaller_unsigned_type;
  typedef unsigned int other_type;
  static const signed int min = INT_MIN;
  static const signed int max = INT_MAX;
};

template <>
struct C_Integer<signed long> : public True {
  enum { is_signed = true };
  typedef signed int smaller_type;
  typedef signed int smaller_signed_type;
  typedef unsigned int smaller_unsigned_type;
  typedef unsigned long other_type;
  static const signed long min = LONG_MIN;
  static const signed long max = LONG_MAX;
};

template <>
struct C_Integer<signed long long> : public True {
  enum { is_signed = true };
  typedef signed long smaller_type;
  typedef signed long smaller_signed_type;
  typedef unsigned long smaller_unsigned_type;
  typedef unsigned long long other_type;
  static const signed long long min = LLONG_MIN;
  static const signed long long max = LLONG_MAX;
};

template <>
struct C_Integer<unsigned char> : public True {
  enum { is_signed = false };
  typedef void smaller_type;
  typedef void smaller_signed_type;
  typedef void smaller_unsigned_type;
  typedef signed char other_type;
  static const unsigned char min = 0;
  static const unsigned char max = UCHAR_MAX;
};

template <>
struct C_Integer<unsigned short> : public True {
  enum { is_signed = false };
  typedef unsigned char smaller_type;
  typedef signed char smaller_signed_type;
  typedef unsigned char smaller_unsigned_type;
  typedef signed short other_type;
  static const unsigned short min = 0;
  static const unsigned short max = USHRT_MAX;
};

template <>
struct C_Integer<unsigned int> : public True {
  enum { is_signed = false };
  typedef unsigned short smaller_type;
  typedef signed short smaller_signed_type;
  typedef unsigned short smaller_unsigned_type;
  typedef signed int other_type;
  static const unsigned int min = 0;
  static const unsigned int max = UINT_MAX;
};

template <>
struct C_Integer<unsigned long> : public True {
  enum { is_signed = false };
  typedef unsigned int smaller_type;
  typedef signed int smaller_signed_type;
  typedef unsigned int smaller_unsigned_type;
  typedef signed long other_type;
  static const unsigned long min = 0;
  static const unsigned long max = ULONG_MAX;
};

template <>
struct C_Integer<unsigned long long> : public True {
  enum { is_signed = false };
  typedef unsigned long smaller_type;
  typedef signed long smaller_signed_type;
  typedef unsigned long smaller_unsigned_type;
  typedef signed long long other_type;
  static const unsigned long long min = 0;
  static const unsigned long long max = ULLONG_MAX;
};

} // namespace Parma_Polyhedra_Library

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

namespace Parma_Polyhedra_Library {

namespace Checked {

template <typename T1, typename T2>
struct Safe_Conversion : public False {
};
template <typename T>
struct Safe_Conversion<T, T> : public True {
};

#define PPL_SAFE_CONVERSION(To, From)					\
  template <> struct Safe_Conversion<To, From> : public True { }

PPL_SAFE_CONVERSION(signed short, signed char);
#if PPL_SIZEOF_CHAR < PPL_SIZEOF_SHORT
PPL_SAFE_CONVERSION(signed short, unsigned char);
#endif

PPL_SAFE_CONVERSION(signed int, signed char);
PPL_SAFE_CONVERSION(signed int, signed short);
#if PPL_SIZEOF_CHAR < PPL_SIZEOF_INT
PPL_SAFE_CONVERSION(signed int, unsigned char);
#endif
#if PPL_SIZEOF_SHORT < PPL_SIZEOF_INT
PPL_SAFE_CONVERSION(signed int, unsigned short);
#endif

PPL_SAFE_CONVERSION(signed long, signed char);
PPL_SAFE_CONVERSION(signed long, signed short);
PPL_SAFE_CONVERSION(signed long, signed int);
#if PPL_SIZEOF_CHAR < PPL_SIZEOF_LONG
PPL_SAFE_CONVERSION(signed long, unsigned char);
#endif
#if PPL_SIZEOF_SHORT < PPL_SIZEOF_LONG
PPL_SAFE_CONVERSION(signed long, unsigned short);
#endif
#if PPL_SIZEOF_INT < PPL_SIZEOF_LONG
PPL_SAFE_CONVERSION(signed long, unsigned int);
#endif

PPL_SAFE_CONVERSION(signed long long, signed char);
PPL_SAFE_CONVERSION(signed long long, signed short);
PPL_SAFE_CONVERSION(signed long long, signed int);
PPL_SAFE_CONVERSION(signed long long, signed long);
#if PPL_SIZEOF_CHAR < PPL_SIZEOF_LONG_LONG
PPL_SAFE_CONVERSION(signed long long, unsigned char);
#endif
#if PPL_SIZEOF_SHORT < PPL_SIZEOF_LONG_LONG
PPL_SAFE_CONVERSION(signed long long, unsigned short);
#endif
#if PPL_SIZEOF_INT < PPL_SIZEOF_LONG_LONG
PPL_SAFE_CONVERSION(signed long long, unsigned int);
#endif
#if PPL_SIZEOF_LONG < PPL_SIZEOF_LONG_LONG
PPL_SAFE_CONVERSION(signed long long, unsigned long);
#endif

PPL_SAFE_CONVERSION(unsigned short, unsigned char);

PPL_SAFE_CONVERSION(unsigned int, unsigned char);
PPL_SAFE_CONVERSION(unsigned int, unsigned short);

PPL_SAFE_CONVERSION(unsigned long, unsigned char);
PPL_SAFE_CONVERSION(unsigned long, unsigned short);
PPL_SAFE_CONVERSION(unsigned long, unsigned int);

PPL_SAFE_CONVERSION(unsigned long long, unsigned char);
PPL_SAFE_CONVERSION(unsigned long long, unsigned short);
PPL_SAFE_CONVERSION(unsigned long long, unsigned int);
PPL_SAFE_CONVERSION(unsigned long long, unsigned long);


#if PPL_SIZEOF_CHAR <= PPL_SIZEOF_FLOAT - 2
PPL_SAFE_CONVERSION(float, signed char);
PPL_SAFE_CONVERSION(float, unsigned char);
#endif
#if PPL_SIZEOF_SHORT <= PPL_SIZEOF_FLOAT - 2
PPL_SAFE_CONVERSION(float, signed short);
PPL_SAFE_CONVERSION(float, unsigned short);
#endif
#if PPL_SIZEOF_INT <= PPL_SIZEOF_FLOAT - 2
PPL_SAFE_CONVERSION(float, signed int);
PPL_SAFE_CONVERSION(float, unsigned int);
#endif
#if PPL_SIZEOF_LONG <= PPL_SIZEOF_FLOAT - 2
PPL_SAFE_CONVERSION(float, signed long);
PPL_SAFE_CONVERSION(float, unsigned long);
#endif
#if PPL_SIZEOF_LONG_LONG <= PPL_SIZEOF_FLOAT - 2
PPL_SAFE_CONVERSION(float, signed long long);
PPL_SAFE_CONVERSION(float, unsigned long long);
#endif

#if PPL_SIZEOF_CHAR <= PPL_SIZEOF_DOUBLE - 4
PPL_SAFE_CONVERSION(double, signed char);
PPL_SAFE_CONVERSION(double, unsigned char);
#endif
#if PPL_SIZEOF_SHORT <= PPL_SIZEOF_DOUBLE - 4
PPL_SAFE_CONVERSION(double, signed short);
PPL_SAFE_CONVERSION(double, unsigned short);
#endif
#if PPL_SIZEOF_INT <= PPL_SIZEOF_DOUBLE - 4
PPL_SAFE_CONVERSION(double, signed int);
PPL_SAFE_CONVERSION(double, unsigned int);
#endif
#if PPL_SIZEOF_LONG <= PPL_SIZEOF_DOUBLE - 4
PPL_SAFE_CONVERSION(double, signed long);
PPL_SAFE_CONVERSION(double, unsigned long);
#endif
#if PPL_SIZEOF_LONG_LONG <= PPL_SIZEOF_DOUBLE - 4
PPL_SAFE_CONVERSION(double, signed long long);
PPL_SAFE_CONVERSION(double, unsigned long long);
#endif
PPL_SAFE_CONVERSION(double, float);

#if PPL_SIZEOF_CHAR <= PPL_SIZEOF_LONG_DOUBLE - 4
PPL_SAFE_CONVERSION(long double, signed char);
PPL_SAFE_CONVERSION(long double, unsigned char);
#endif
#if PPL_SIZEOF_SHORT <= PPL_SIZEOF_LONG_DOUBLE - 4
PPL_SAFE_CONVERSION(long double, signed short);
PPL_SAFE_CONVERSION(long double, unsigned short);
#endif
#if PPL_SIZEOF_INT <= PPL_SIZEOF_LONG_DOUBLE - 4
PPL_SAFE_CONVERSION(long double, signed int);
PPL_SAFE_CONVERSION(long double, unsigned int);
#endif
#if PPL_SIZEOF_LONG <= PPL_SIZEOF_LONG_DOUBLE - 4
PPL_SAFE_CONVERSION(long double, signed long);
PPL_SAFE_CONVERSION(long double, unsigned long);
#endif
#if PPL_SIZEOF_LONG_LONG <= PPL_SIZEOF_LONG_DOUBLE - 4
PPL_SAFE_CONVERSION(long double, signed long long);
PPL_SAFE_CONVERSION(long double, unsigned long long);
#endif
PPL_SAFE_CONVERSION(long double, float);
PPL_SAFE_CONVERSION(long double, double);

PPL_SAFE_CONVERSION(mpz_class, signed char);
PPL_SAFE_CONVERSION(mpz_class, signed short);
PPL_SAFE_CONVERSION(mpz_class, signed int);
PPL_SAFE_CONVERSION(mpz_class, signed long);
//PPL_SAFE_CONVERSION(mpz_class, signed long long);
PPL_SAFE_CONVERSION(mpz_class, unsigned char);
PPL_SAFE_CONVERSION(mpz_class, unsigned short);
PPL_SAFE_CONVERSION(mpz_class, unsigned int);
PPL_SAFE_CONVERSION(mpz_class, unsigned long);
//PPL_SAFE_CONVERSION(mpz_class, unsigned long long);

PPL_SAFE_CONVERSION(mpq_class, signed char);
PPL_SAFE_CONVERSION(mpq_class, signed short);
PPL_SAFE_CONVERSION(mpq_class, signed int);
PPL_SAFE_CONVERSION(mpq_class, signed long);
//PPL_SAFE_CONVERSION(mpq_class, signed long long);
PPL_SAFE_CONVERSION(mpq_class, unsigned char);
PPL_SAFE_CONVERSION(mpq_class, unsigned short);
PPL_SAFE_CONVERSION(mpq_class, unsigned int);
PPL_SAFE_CONVERSION(mpq_class, unsigned long);
//PPL_SAFE_CONVERSION(mpq_class, unsigned long long);
PPL_SAFE_CONVERSION(mpq_class, float);
PPL_SAFE_CONVERSION(mpq_class, double);
//PPL_SAFE_CONVERSION(mpq_class, long double);

#undef PPL_SAFE_CONVERSION

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

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

template <typename To_Policy, typename To>
struct PPL_FUNCTION_CLASS(construct_special) {
  static inline Result function(To& to, Result r, Rounding_Dir dir) {
    new (&to) To();
    return assign_special<To_Policy>(to, r, dir);
  }
};

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

template <typename To_Policy, typename From_Policy, typename Type>
inline typename Enable_If<Is_Same<To_Policy, From_Policy>::value, void>::type
copy_generic(Type& to, const Type& from) {
  to = from;
}

template <typename To_Policy, typename From_Policy, typename To, typename From>
inline Result
abs_generic(To& to, const From& from, Rounding_Dir dir) {
  if (from < 0)
    return neg<To_Policy, From_Policy>(to, from, dir);
  else
    return assign<To_Policy, From_Policy>(to, from, dir);
}

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 To_Policy, typename From1_Policy, typename From2_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 IEC 559 floating point numbers.
    rem<To_Policy, From1_Policy, From2_Policy>(rm, nx, ny, ROUND_NOT_NEEDED);
    nx = ny;
    ny = rm;
  }
  to = nx;
}

template <typename To_Policy, typename From1_Policy, typename From2_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<To_Policy, From1_Policy, From2_Policy>(to, x, y);
  return abs<To_Policy, To_Policy>(to, to, dir);
}

template <typename To1_Policy, typename To2_Policy, typename To3_Policy,
	  typename From1_Policy, typename From2_Policy,
	  typename To1, typename To2, typename To3,
	  typename From1, typename From2>
inline Result
gcdext_exact(To1& to, To2& s, To3& t, const From1& x, const From2& y,
	     Rounding_Dir dir) {
  // In case this becomes a bottleneck, we may consider using the
  // Stehle'-Zimmermann algorithm (see R. Crandall and C. Pomerance,
  // Prime Numbers - A Computational Perspective, Second Edition,
  // Springer, 2005).
  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<To1_Policy, From1_Policy>(to, x, dir);
    }
  }

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

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

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

  // If PPL_MATCH_GMP_GCDEXT is defined then s is favored 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 behavior of GMP.
#define PPL_MATCH_GMP_GCDEXT 1
#ifdef PPL_MATCH_GMP_GCDEXT
  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 PPL_MATCH_GMP_GCDEXT
 sign_check:
#endif
  if (negative_x) {
    r = neg<To2_Policy, To2_Policy>(s, s, dir);
    if (r != V_EQ)
      return r;
  }
  if (negative_y)
    return neg<To3_Policy, To3_Policy>(t, t, dir);
  return V_EQ;
#undef PPL_MATCH_GMP_GCDEXT
}

template <typename To_Policy, typename From1_Policy, typename From2_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<From1_Policy, From1_Policy>(nx, x, dir);
  if (r != V_EQ)
    return r;
  r = abs<From2_Policy, From2_Policy>(ny, y, dir);
  if (r != V_EQ)
    return r;
  To gcd;
  gcd_exact_noabs<To_Policy, From1_Policy, From2_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 IEC 559 floating point numbers.
  div<To_Policy, From1_Policy, To_Policy>(to, nx, gcd, ROUND_NOT_NEEDED);
  return mul<To_Policy, To_Policy, From2_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 T1, typename T2, typename Enable = void>
struct Safe_Int_Comparison : public False {
};

template <typename T1, typename T2>
struct Safe_Int_Comparison<T1, T2, typename Enable_If<(C_Integer<T1>::value && C_Integer<T2>::value)>::type>
  : public Bool<(C_Integer<T1>::is_signed
		 ? (C_Integer<T2>::is_signed
		    || sizeof(T2) < sizeof(T1)
		    || sizeof(T2) < sizeof(int))
		 : (!C_Integer<T2>::is_signed
		    || sizeof(T1) < sizeof(T2)
		    || sizeof(T1) < sizeof(int)))> {
};


template <typename T1, typename T2>
inline typename Enable_If<(Safe_Int_Comparison<T1, T2>::value
			   || Safe_Conversion<T1, T2>::value
			   || Safe_Conversion<T2, T1>::value), bool>::type
lt(const T1& x, const T2& y) {
  return x < y;
}
template <typename T1, typename T2>
inline typename Enable_If<(Safe_Int_Comparison<T1, T2>::value
			   || Safe_Conversion<T1, T2>::value
			   || Safe_Conversion<T2, T1>::value), bool>::type
le(const T1& x, const T2& y) {
  return x <= y;
}
template <typename T1, typename T2>
inline typename Enable_If<(Safe_Int_Comparison<T1, T2>::value
			   || Safe_Conversion<T1, T2>::value
			   || Safe_Conversion<T2, T1>::value), bool>::type
eq(const T1& x, const T2& y) {
  return x == y;
}

template <typename S, typename U>
inline typename Enable_If<(!Safe_Int_Comparison<S, U>::value
			   && C_Integer<U>::value
			   && C_Integer<S>::is_signed), bool>::type
lt(const S& x, const U& y) {
  return x < 0 || x < y;
}

template <typename U, typename S>
inline typename Enable_If<(!Safe_Int_Comparison<S, U>::value
			   && C_Integer<U>::value
			   && C_Integer<S>::is_signed), bool>::type
lt(const U& x, const S& y) {
  return y >= 0 && x < y;
}

template <typename S, typename U>
inline typename Enable_If<(!Safe_Int_Comparison<S, U>::value
			   && C_Integer<U>::value
			   && C_Integer<S>::is_signed), bool>::type
le(const S& x, const U& y) {
  return x < 0 || x <= y;
}

template <typename U, typename S>
inline typename Enable_If<(!Safe_Int_Comparison<S, U>::value
			   && C_Integer<U>::value
			   && C_Integer<S>::is_signed), bool>::type
le(const U& x, const S& y) {
  return y >= 0 && x <= y;
}

template <typename S, typename U>
inline typename Enable_If<(!Safe_Int_Comparison<S, U>::value
			   && C_Integer<U>::value
			   && C_Integer<S>::is_signed), bool>::type
eq(const S& x, const U& y) {
  return x >= 0 && x == y;
}

template <typename U, typename S>
inline typename Enable_If<(!Safe_Int_Comparison<S, U>::value
			   && C_Integer<U>::value
			   && C_Integer<S>::is_signed), bool>::type
eq(const U& x, const S& y) {
  return y >= 0 && x == y;
}

template <typename T1, typename T2>
inline typename Enable_If<(!Safe_Conversion<T1, T2>::value
			   && !Safe_Conversion<T2, T1>::value
			   && (!C_Integer<T1>::value || !C_Integer<T2>::value)), bool>::type
eq(const T1& x, const T2& y) {
  PPL_DIRTY_TEMP(T1, tmp);
  Result r = assign_r(tmp, y, static_cast<Rounding_Dir>(ROUND_DIRECT | ROUND_FPU_CHECK_INEXACT));
  // FIXME: We can do this also without fpu inexact check using a
  // conversion back and forth and then testing equality.  We should
  // code this in checked_float.inlines.hh, probably it's faster also
  // if fpu supports inexact check.
  assert(r != V_LE && r != V_GE && r != V_LGE);
  return r == V_EQ && x == tmp;
}

template <typename T1, typename T2>
inline typename Enable_If<(!Safe_Conversion<T1, T2>::value
			   && !Safe_Conversion<T2, T1>::value
			   && (!C_Integer<T1>::value || !C_Integer<T2>::value)), bool>::type
lt(const T1& x, const T2& y) {
  PPL_DIRTY_TEMP(T1, tmp);
  Result r = assign_r(tmp, y, ROUND_UP);
  switch (r) {
  case V_POS_OVERFLOW:
  case VC_PLUS_INFINITY:
    return true;
  case V_EQ:
  case V_LT:
  case V_LE:
    return x < tmp;
  default:
    return false;
  }
}

template <typename T1, typename T2>
inline typename
Enable_If<(!Safe_Conversion<T1, T2>::value
           && !Safe_Conversion<T2, T1>::value
           && (!C_Integer<T1>::value || !C_Integer<T2>::value)), bool>::type
le(const T1& x, const T2& y) {
  PPL_DIRTY_TEMP(T1, tmp);
  Result r
    = assign_r(tmp,
               y,
               static_cast<Rounding_Dir>(ROUND_UP | ROUND_FPU_CHECK_INEXACT));
  switch (r) {
  case V_POS_OVERFLOW:
  case VC_PLUS_INFINITY:
    return true;
  case V_EQ:
    return x <= tmp;
  case V_LT:
    return x < tmp;
  case V_LE:
  case V_GE:
  case V_LGE:
    // FIXME: See comment above.
    assert(0);
  default:
    return false;
  }
}

template <typename Policy1, typename Policy2,
	  typename Type1, typename Type2>
inline bool
lt_p(const Type1& x, const Type2& y) {
  return lt(x, y);
}

template <typename Policy1, typename Policy2,
	  typename Type1, typename Type2>
inline bool
le_p(const Type1& x, const Type2& y) {
  return le(x, y);
}

template <typename Policy1, typename Policy2,
	  typename Type1, typename Type2>
inline bool
eq_p(const Type1& x, const Type2& y) {
  return eq(x, y);
}

template <typename Policy1, typename Policy2,
	  typename Type1, typename Type2>
inline Result
cmp_generic(const Type1& x, const Type2& y) {
  if (lt(y, x))
    return V_GT;
  if (lt(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) {
  PPL_DIRTY_TEMP0(mpq_class, q);
  Result r = input_mpq(q, is);
  if (is_special(r))
    return assign_special<Policy>(to, r, dir);
  if (r == V_EQ)
    return assign<Policy, void>(to, q, dir);
  assert(0);
  return VC_NAN;
}

} // 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/checked_int.inlines.hh line 27. */
#include <cerrno>
#include <cstdlib>
#include <climits>
#include <string>

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

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

namespace Parma_Polyhedra_Library {

namespace Checked {

#ifndef PPL_HAVE_INT_FAST16_T
typedef int16_t int_fast16_t;
#endif

#ifndef PPL_HAVE_INT_FAST32_T
typedef int32_t int_fast32_t;
#endif

#ifndef PPL_HAVE_INT_FAST64_T
typedef int64_t int_fast64_t;
#endif

#ifndef PPL_HAVE_UINT_FAST16_T
typedef uint16_t uint_fast16_t;
#endif

#ifndef PPL_HAVE_UINT_FAST32_T
typedef uint32_t uint_fast32_t;
#endif

#ifndef PPL_HAVE_UINT_FAST64_T
typedef uint64_t uint_fast64_t;
#endif

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

template <typename Policy, typename To>
inline Result
set_neg_overflow_int(To& to, Rounding_Dir dir) {
  if (round_up(dir)) {
    to = Extended_Int<Policy, To>::min;
    return V_LT;
  }
  else {
    if (Policy::has_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 (round_down(dir)) {
    to = Extended_Int<Policy, To>::max;
    return V_GT;
  }
  else {
    if (Policy::has_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 (round_down(dir)) {
    --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 (round_up(dir)) {
    ++to;
    return V_LT;
  }
  return V_GT;
}

template <typename Policy, typename To>
inline Result
round_lt_int(To& to, Rounding_Dir dir) {
  if (round_down(dir)) {
    if (to == Extended_Int<Policy, To>::min) {
      if (Policy::has_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 (round_up(dir)) {
    if (to == Extended_Int<Policy, To>::max) {
      if (Policy::has_infinity) {
	to = Extended_Int<Policy, To>::plus_infinity;
	return V_LT;
      }
      return V_POS_OVERFLOW;
    }
    else {
      ++to;
      return V_LT;
    }
  }
  return V_GT;
}

PPL_SPECIALIZE_COPY(copy_generic, signed char)
PPL_SPECIALIZE_COPY(copy_generic, signed short)
PPL_SPECIALIZE_COPY(copy_generic, signed int)
PPL_SPECIALIZE_COPY(copy_generic, signed long)
PPL_SPECIALIZE_COPY(copy_generic, signed long long)
PPL_SPECIALIZE_COPY(copy_generic, unsigned char)
PPL_SPECIALIZE_COPY(copy_generic, unsigned short)
PPL_SPECIALIZE_COPY(copy_generic, unsigned int)
PPL_SPECIALIZE_COPY(copy_generic, unsigned long)
PPL_SPECIALIZE_COPY(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::has_nan
      && (nan || sign)
      && v == Extended_Int<Policy, Type>::not_a_number)
    return VC_NAN;
  if (!inf & !sign)
    return VC_NORMAL;
  if (Policy::has_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;
}

PPL_SPECIALIZE_CLASSIFY(classify_int, signed char)
PPL_SPECIALIZE_CLASSIFY(classify_int, signed short)
PPL_SPECIALIZE_CLASSIFY(classify_int, signed int)
PPL_SPECIALIZE_CLASSIFY(classify_int, signed long)
PPL_SPECIALIZE_CLASSIFY(classify_int, signed long long)
PPL_SPECIALIZE_CLASSIFY(classify_int, unsigned char)
PPL_SPECIALIZE_CLASSIFY(classify_int, unsigned short)
PPL_SPECIALIZE_CLASSIFY(classify_int, unsigned int)
PPL_SPECIALIZE_CLASSIFY(classify_int, unsigned long)
PPL_SPECIALIZE_CLASSIFY(classify_int, unsigned long long)

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

PPL_SPECIALIZE_IS_NAN(is_nan_int, signed char)
PPL_SPECIALIZE_IS_NAN(is_nan_int, signed short)
PPL_SPECIALIZE_IS_NAN(is_nan_int, signed int)
PPL_SPECIALIZE_IS_NAN(is_nan_int, signed long)
PPL_SPECIALIZE_IS_NAN(is_nan_int, signed long long)
PPL_SPECIALIZE_IS_NAN(is_nan_int, unsigned char)
PPL_SPECIALIZE_IS_NAN(is_nan_int, unsigned short)
PPL_SPECIALIZE_IS_NAN(is_nan_int, unsigned int)
PPL_SPECIALIZE_IS_NAN(is_nan_int, unsigned long)
PPL_SPECIALIZE_IS_NAN(is_nan_int, unsigned long long)

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

PPL_SPECIALIZE_IS_MINF(is_minf_int, signed char)
PPL_SPECIALIZE_IS_MINF(is_minf_int, signed short)
PPL_SPECIALIZE_IS_MINF(is_minf_int, signed int)
PPL_SPECIALIZE_IS_MINF(is_minf_int, signed long)
PPL_SPECIALIZE_IS_MINF(is_minf_int, signed long long)
PPL_SPECIALIZE_IS_MINF(is_minf_int, unsigned char)
PPL_SPECIALIZE_IS_MINF(is_minf_int, unsigned short)
PPL_SPECIALIZE_IS_MINF(is_minf_int, unsigned int)
PPL_SPECIALIZE_IS_MINF(is_minf_int, unsigned long)
PPL_SPECIALIZE_IS_MINF(is_minf_int, unsigned long long)

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

PPL_SPECIALIZE_IS_PINF(is_pinf_int, signed char)
PPL_SPECIALIZE_IS_PINF(is_pinf_int, signed short)
PPL_SPECIALIZE_IS_PINF(is_pinf_int, signed int)
PPL_SPECIALIZE_IS_PINF(is_pinf_int, signed long)
PPL_SPECIALIZE_IS_PINF(is_pinf_int, signed long long)
PPL_SPECIALIZE_IS_PINF(is_pinf_int, unsigned char)
PPL_SPECIALIZE_IS_PINF(is_pinf_int, unsigned short)
PPL_SPECIALIZE_IS_PINF(is_pinf_int, unsigned int)
PPL_SPECIALIZE_IS_PINF(is_pinf_int, unsigned long)
PPL_SPECIALIZE_IS_PINF(is_pinf_int, unsigned long long)

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

PPL_SPECIALIZE_IS_INT(is_int_int, signed char)
PPL_SPECIALIZE_IS_INT(is_int_int, signed short)
PPL_SPECIALIZE_IS_INT(is_int_int, signed int)
PPL_SPECIALIZE_IS_INT(is_int_int, signed long)
PPL_SPECIALIZE_IS_INT(is_int_int, signed long long)
PPL_SPECIALIZE_IS_INT(is_int_int, unsigned char)
PPL_SPECIALIZE_IS_INT(is_int_int, unsigned short)
PPL_SPECIALIZE_IS_INT(is_int_int, unsigned int)
PPL_SPECIALIZE_IS_INT(is_int_int, unsigned long)
PPL_SPECIALIZE_IS_INT(is_int_int, unsigned long long)

template <typename Policy, typename Type>
inline Result
assign_special_int(Type& v, Result r, Rounding_Dir dir) {
  Result t = classify(r);
  switch (t) {
  case VC_NAN:
    if (Policy::has_nan)
      v = Extended_Int<Policy, Type>::not_a_number;
    break;
  case VC_MINUS_INFINITY:
    if (Policy::has_infinity) {
      v = Extended_Int<Policy, Type>::minus_infinity;
      return V_EQ;
    }
    if (round_up(dir)) {
      v = Extended_Int<Policy, Type>::min;
      return V_LT;
    }
    break;
  case VC_PLUS_INFINITY:
    if (Policy::has_infinity) {
      v = Extended_Int<Policy, Type>::plus_infinity;
      return V_EQ;
    }
    if (round_down(dir)) {
      v = Extended_Int<Policy, Type>::max;
      return V_GT;
    }
    break;
  default:
    assert(0);
    break;
  }
  return r;
}

PPL_SPECIALIZE_ASSIGN_SPECIAL(assign_special_int, signed char)
PPL_SPECIALIZE_ASSIGN_SPECIAL(assign_special_int, signed short)
PPL_SPECIALIZE_ASSIGN_SPECIAL(assign_special_int, signed int)
PPL_SPECIALIZE_ASSIGN_SPECIAL(assign_special_int, signed long)
PPL_SPECIALIZE_ASSIGN_SPECIAL(assign_special_int, signed long long)
PPL_SPECIALIZE_ASSIGN_SPECIAL(assign_special_int, unsigned char)
PPL_SPECIALIZE_ASSIGN_SPECIAL(assign_special_int, unsigned short)
PPL_SPECIALIZE_ASSIGN_SPECIAL(assign_special_int, unsigned int)
PPL_SPECIALIZE_ASSIGN_SPECIAL(assign_special_int, unsigned long)
PPL_SPECIALIZE_ASSIGN_SPECIAL(assign_special_int, unsigned long long)

template <typename To_Policy, typename From_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)
      || (sizeof(To) == sizeof(From)
	  && (Extended_Int<To_Policy, To>::min > Extended_Int<From_Policy, From>::min
	      || Extended_Int<To_Policy, To>::max < Extended_Int<From_Policy, From>::max))) {
    if (CHECK_P(To_Policy::check_overflow,
		from < static_cast<From>(Extended_Int<To_Policy, To>::min)))
      return set_neg_overflow_int<To_Policy>(to, dir);
    if (CHECK_P(To_Policy::check_overflow,
		from > static_cast<From>(Extended_Int<To_Policy, To>::max)))
      return set_pos_overflow_int<To_Policy>(to, dir);
  }
  to = To(from);
  return V_EQ;
}

template <typename To_Policy, typename From_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(To_Policy::check_overflow,
		from > static_cast<From>(Extended_Int<To_Policy, To>::max)))
      return set_pos_overflow_int<To_Policy>(to, dir);
  }
  to = To(from);
  return V_EQ;
}

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

template <typename To_Policy, typename From_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)
      || (sizeof(To) == sizeof(From)
	  && Extended_Int<To_Policy, To>::max < Extended_Int<From_Policy, From>::max)) {
    if (CHECK_P(To_Policy::check_overflow,
		from > static_cast<From>(Extended_Int<To_Policy, To>::max)))
      return set_pos_overflow_int<To_Policy>(to, dir);
  }
  to = To(from);
  return V_EQ;
}


#define PPL_ASSIGN2_SIGNED_SIGNED(Smaller, Larger) \
PPL_SPECIALIZE_ASSIGN(assign_signed_int_signed_int, Smaller, Larger) \
PPL_SPECIALIZE_ASSIGN(assign_signed_int_signed_int, Larger, Smaller)

#define PPL_ASSIGN2_UNSIGNED_UNSIGNED(Smaller, Larger) \
PPL_SPECIALIZE_ASSIGN(assign_unsigned_int_unsigned_int, Smaller, Larger) \
PPL_SPECIALIZE_ASSIGN(assign_unsigned_int_unsigned_int, Larger, Smaller)

#define PPL_ASSIGN2_UNSIGNED_SIGNED(Smaller, Larger) \
PPL_SPECIALIZE_ASSIGN(assign_unsigned_int_signed_int, Smaller, Larger) \
PPL_SPECIALIZE_ASSIGN(assign_signed_int_unsigned_int, Larger, Smaller)

#define PPL_ASSIGN2_SIGNED_UNSIGNED(Smaller, Larger) \
PPL_SPECIALIZE_ASSIGN(assign_signed_int_unsigned_int, Smaller, Larger) \
PPL_SPECIALIZE_ASSIGN(assign_unsigned_int_signed_int, Larger, Smaller)

#define PPL_ASSIGN_SIGNED(Type) \
PPL_SPECIALIZE_ASSIGN(assign_signed_int_signed_int, Type, Type)
#define PPL_ASSIGN_UNSIGNED(Type) \
PPL_SPECIALIZE_ASSIGN(assign_unsigned_int_unsigned_int, Type, Type)

PPL_ASSIGN_SIGNED(signed char)
PPL_ASSIGN_SIGNED(signed short)
PPL_ASSIGN_SIGNED(signed int)
PPL_ASSIGN_SIGNED(signed long)
PPL_ASSIGN_SIGNED(signed long long)
PPL_ASSIGN_UNSIGNED(unsigned char)
PPL_ASSIGN_UNSIGNED(unsigned short)
PPL_ASSIGN_UNSIGNED(unsigned int)
PPL_ASSIGN_UNSIGNED(unsigned long)
PPL_ASSIGN_UNSIGNED(unsigned long long)

PPL_ASSIGN2_SIGNED_SIGNED(signed char, signed short)
PPL_ASSIGN2_SIGNED_SIGNED(signed char, signed int)
PPL_ASSIGN2_SIGNED_SIGNED(signed char, signed long)
PPL_ASSIGN2_SIGNED_SIGNED(signed char, signed long long)
PPL_ASSIGN2_SIGNED_SIGNED(signed short, signed int)
PPL_ASSIGN2_SIGNED_SIGNED(signed short, signed long)
PPL_ASSIGN2_SIGNED_SIGNED(signed short, signed long long)
PPL_ASSIGN2_SIGNED_SIGNED(signed int, signed long)
PPL_ASSIGN2_SIGNED_SIGNED(signed int, signed long long)
PPL_ASSIGN2_SIGNED_SIGNED(signed long, signed long long)
PPL_ASSIGN2_UNSIGNED_UNSIGNED(unsigned char, unsigned short)
PPL_ASSIGN2_UNSIGNED_UNSIGNED(unsigned char, unsigned int)
PPL_ASSIGN2_UNSIGNED_UNSIGNED(unsigned char, unsigned long)
PPL_ASSIGN2_UNSIGNED_UNSIGNED(unsigned char, unsigned long long)
PPL_ASSIGN2_UNSIGNED_UNSIGNED(unsigned short, unsigned int)
PPL_ASSIGN2_UNSIGNED_UNSIGNED(unsigned short, unsigned long)
PPL_ASSIGN2_UNSIGNED_UNSIGNED(unsigned short, unsigned long long)
PPL_ASSIGN2_UNSIGNED_UNSIGNED(unsigned int, unsigned long)
PPL_ASSIGN2_UNSIGNED_UNSIGNED(unsigned int, unsigned long long)
PPL_ASSIGN2_UNSIGNED_UNSIGNED(unsigned long, unsigned long long)
PPL_ASSIGN2_UNSIGNED_SIGNED(unsigned char, signed short)
PPL_ASSIGN2_UNSIGNED_SIGNED(unsigned char, signed int)
PPL_ASSIGN2_UNSIGNED_SIGNED(unsigned char, signed long)
PPL_ASSIGN2_UNSIGNED_SIGNED(unsigned char, signed long long)
PPL_ASSIGN2_UNSIGNED_SIGNED(unsigned short, signed int)
PPL_ASSIGN2_UNSIGNED_SIGNED(unsigned short, signed long)
PPL_ASSIGN2_UNSIGNED_SIGNED(unsigned short, signed long long)
PPL_ASSIGN2_UNSIGNED_SIGNED(unsigned int, signed long)
PPL_ASSIGN2_UNSIGNED_SIGNED(unsigned int, signed long long)
PPL_ASSIGN2_UNSIGNED_SIGNED(unsigned long, signed long long)
PPL_ASSIGN2_SIGNED_UNSIGNED(signed char, unsigned char)
PPL_ASSIGN2_SIGNED_UNSIGNED(signed char, unsigned short)
PPL_ASSIGN2_SIGNED_UNSIGNED(signed char, unsigned int)
PPL_ASSIGN2_SIGNED_UNSIGNED(signed char, unsigned long)
PPL_ASSIGN2_SIGNED_UNSIGNED(signed char, unsigned long long)
PPL_ASSIGN2_SIGNED_UNSIGNED(signed short, unsigned short)
PPL_ASSIGN2_SIGNED_UNSIGNED(signed short, unsigned int)
PPL_ASSIGN2_SIGNED_UNSIGNED(signed short, unsigned long)
PPL_ASSIGN2_SIGNED_UNSIGNED(signed short, unsigned long long)
PPL_ASSIGN2_SIGNED_UNSIGNED(signed int, unsigned int)
PPL_ASSIGN2_SIGNED_UNSIGNED(signed int, unsigned long)
PPL_ASSIGN2_SIGNED_UNSIGNED(signed int, unsigned long long)
PPL_ASSIGN2_SIGNED_UNSIGNED(signed long, unsigned long)
PPL_ASSIGN2_SIGNED_UNSIGNED(signed long, unsigned long long)
PPL_ASSIGN2_SIGNED_UNSIGNED(signed long long, unsigned long long)

template <typename To_Policy, typename From_Policy, typename To, typename From>
inline Result
assign_int_float(To& to, const From from, Rounding_Dir dir) {
  if (is_nan<From_Policy>(from))
    return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
  else if (is_minf<From_Policy>(from))
    return assign_special<To_Policy>(to, VC_MINUS_INFINITY, dir);
  else if (is_pinf<From_Policy>(from))
    return assign_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
#if 0
  // FIXME: this is correct but it is inefficient and breaks the build
  // for the missing definition of static const members (a problem present
  // also in other areas of the PPL).
  if (CHECK_P(To_Policy::check_overflow, lt(from, Extended_Int<To_Policy, To>::min)))
    return set_neg_overflow_int<To_Policy>(to, dir);
  if (CHECK_P(To_Policy::check_overflow, !le(from, Extended_Int<To_Policy, To>::max)))
    return set_pos_overflow_int<To_Policy>(to, dir);
#else
  if (CHECK_P(To_Policy::check_overflow, (from < Extended_Int<To_Policy, To>::min)))
    return set_neg_overflow_int<To_Policy>(to, dir);
  if (CHECK_P(To_Policy::check_overflow, (from > Extended_Int<To_Policy, To>::max)))
    return set_pos_overflow_int<To_Policy>(to, dir);
#endif
  From i_from = rint(from);
  to = static_cast<To>(i_from);
  if (round_ignore(dir))
    return V_LGE;
  if (from < i_from)
    return round_lt_int<To_Policy>(to, dir);
  else if (from > i_from)
    return round_gt_int<To_Policy>(to, dir);
  else
    return V_EQ;
}

PPL_SPECIALIZE_ASSIGN(assign_int_float, signed char, float)
PPL_SPECIALIZE_ASSIGN(assign_int_float, signed short, float)
PPL_SPECIALIZE_ASSIGN(assign_int_float, signed int, float)
PPL_SPECIALIZE_ASSIGN(assign_int_float, signed long, float)
PPL_SPECIALIZE_ASSIGN(assign_int_float, signed long long, float)
PPL_SPECIALIZE_ASSIGN(assign_int_float, unsigned char, float)
PPL_SPECIALIZE_ASSIGN(assign_int_float, unsigned short, float)
PPL_SPECIALIZE_ASSIGN(assign_int_float, unsigned int, float)
PPL_SPECIALIZE_ASSIGN(assign_int_float, unsigned long, float)
PPL_SPECIALIZE_ASSIGN(assign_int_float, unsigned long long, float)

PPL_SPECIALIZE_ASSIGN(assign_int_float, signed char, double)
PPL_SPECIALIZE_ASSIGN(assign_int_float, signed short, double)
PPL_SPECIALIZE_ASSIGN(assign_int_float, signed int, double)
PPL_SPECIALIZE_ASSIGN(assign_int_float, signed long, double)
PPL_SPECIALIZE_ASSIGN(assign_int_float, signed long long, double)
PPL_SPECIALIZE_ASSIGN(assign_int_float, unsigned char, double)
PPL_SPECIALIZE_ASSIGN(assign_int_float, unsigned short, double)
PPL_SPECIALIZE_ASSIGN(assign_int_float, unsigned int, double)
PPL_SPECIALIZE_ASSIGN(assign_int_float, unsigned long, double)
PPL_SPECIALIZE_ASSIGN(assign_int_float, unsigned long long, double)

PPL_SPECIALIZE_ASSIGN(assign_int_float, signed char, long double)
PPL_SPECIALIZE_ASSIGN(assign_int_float, signed short, long double)
PPL_SPECIALIZE_ASSIGN(assign_int_float, signed int, long double)
PPL_SPECIALIZE_ASSIGN(assign_int_float, signed long, long double)
PPL_SPECIALIZE_ASSIGN(assign_int_float, signed long long, long double)
PPL_SPECIALIZE_ASSIGN(assign_int_float, unsigned char, long double)
PPL_SPECIALIZE_ASSIGN(assign_int_float, unsigned short, long double)
PPL_SPECIALIZE_ASSIGN(assign_int_float, unsigned int, long double)
PPL_SPECIALIZE_ASSIGN(assign_int_float, unsigned long, long double)
PPL_SPECIALIZE_ASSIGN(assign_int_float, unsigned long long, long double)

#undef PPL_ASSIGN_SIGNED
#undef PPL_ASSIGN_UNSIGNED
#undef PPL_ASSIGN2_SIGNED_SIGNED
#undef PPL_ASSIGN2_UNSIGNED_UNSIGNED
#undef PPL_ASSIGN2_UNSIGNED_SIGNED
#undef PPL_ASSIGN2_SIGNED_UNSIGNED

template <typename To_Policy, typename From_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 (!To_Policy::check_overflow) {
      to = from.get_si();
      return V_EQ;
    }
    if (from.fits_slong_p()) {
      signed long v = from.get_si();
      if (v < C_Integer<To>::min)
	return set_neg_overflow_int<To_Policy>(to, dir);
      if (v > C_Integer<To>::max)
	return set_pos_overflow_int<To_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<To_Policy, To_Policy>(to, v, dir);
	to = v;
	return V_EQ;
      }
    }
  }
  return ::sgn(from) < 0
    ? set_neg_overflow_int<To_Policy>(to, dir)
    : set_pos_overflow_int<To_Policy>(to, dir);
}

PPL_SPECIALIZE_ASSIGN(assign_signed_int_mpz, signed char, mpz_class)
PPL_SPECIALIZE_ASSIGN(assign_signed_int_mpz, signed short, mpz_class)
PPL_SPECIALIZE_ASSIGN(assign_signed_int_mpz, signed int, mpz_class)
PPL_SPECIALIZE_ASSIGN(assign_signed_int_mpz, signed long, mpz_class)
PPL_SPECIALIZE_ASSIGN(assign_signed_int_mpz, signed long long, mpz_class)

template <typename To_Policy, typename From_Policy, typename To>
inline Result
assign_unsigned_int_mpz(To& to, const mpz_class& from, Rounding_Dir dir) {
  if (CHECK_P(To_Policy::check_overflow, ::sgn(from) < 0))
    return set_neg_overflow_int<To_Policy>(to, dir);
  if (sizeof(To) <= sizeof(unsigned long)) {
    if (!To_Policy::check_overflow) {
      to = from.get_ui();
      return V_EQ;
    }
    if (from.fits_ulong_p()) {
      unsigned long v = from.get_ui();
      if (v > C_Integer<To>::max)
	return set_pos_overflow_int<To_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<To_Policy>(to, dir);
}

PPL_SPECIALIZE_ASSIGN(assign_unsigned_int_mpz, unsigned char, mpz_class)
PPL_SPECIALIZE_ASSIGN(assign_unsigned_int_mpz, unsigned short, mpz_class)
PPL_SPECIALIZE_ASSIGN(assign_unsigned_int_mpz, unsigned int, mpz_class)
PPL_SPECIALIZE_ASSIGN(assign_unsigned_int_mpz, unsigned long, mpz_class)
PPL_SPECIALIZE_ASSIGN(assign_unsigned_int_mpz, unsigned long long, mpz_class)

template <typename To_Policy, typename From_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();
  PPL_DIRTY_TEMP0(mpz_class, q);
  mpz_ptr _q = q.get_mpz_t();
  if (round_ignore(dir)) {
    mpz_tdiv_q(_q, n, d);
    Result r = assign<To_Policy, void>(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<To_Policy, void>(to, q, dir);
  if (r != V_EQ)
    return r;
  switch (sign) {
  case -1:
    return round_lt_int<To_Policy>(to, dir);
  case 1:
    return round_gt_int<To_Policy>(to, dir);
  default:
    return V_EQ;
  }
}

PPL_SPECIALIZE_ASSIGN(assign_int_mpq, signed char, mpq_class)
PPL_SPECIALIZE_ASSIGN(assign_int_mpq, signed short, mpq_class)
PPL_SPECIALIZE_ASSIGN(assign_int_mpq, signed int, mpq_class)
PPL_SPECIALIZE_ASSIGN(assign_int_mpq, signed long, mpq_class)
PPL_SPECIALIZE_ASSIGN(assign_int_mpq, signed long long, mpq_class)
PPL_SPECIALIZE_ASSIGN(assign_int_mpq, unsigned char, mpq_class)
PPL_SPECIALIZE_ASSIGN(assign_int_mpq, unsigned short, mpq_class)
PPL_SPECIALIZE_ASSIGN(assign_int_mpq, unsigned int, mpq_class)
PPL_SPECIALIZE_ASSIGN(assign_int_mpq, unsigned long, mpq_class)
PPL_SPECIALIZE_ASSIGN(assign_int_mpq, unsigned long long, mpq_class)

#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 architectures.
//
// 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> {
  const_bool_nodef(use_for_neg, true);
  const_bool_nodef(use_for_add, true);
  const_bool_nodef(use_for_sub, true);
  const_bool_nodef(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> {
  const_bool_nodef(use_for_neg, true);
  const_bool_nodef(use_for_add, true);
  const_bool_nodef(use_for_sub, true);
  const_bool_nodef(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> {
  const_bool_nodef(use_for_neg, true);
  const_bool_nodef(use_for_add, true);
  const_bool_nodef(use_for_sub, true);
  const_bool_nodef(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> {
  const_bool_nodef(use_for_neg, true);
  const_bool_nodef(use_for_add, true);
  const_bool_nodef(use_for_sub, true);
  const_bool_nodef(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> {
  const_bool_nodef(use_for_neg, (LONG_BITS == 64));
  const_bool_nodef(use_for_add, (LONG_BITS == 64));
  const_bool_nodef(use_for_sub, (LONG_BITS == 64));
  const_bool_nodef(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> {
  const_bool_nodef(use_for_neg, (LONG_BITS == 64));
  const_bool_nodef(use_for_add, (LONG_BITS == 64));
  const_bool_nodef(use_for_sub, (LONG_BITS == 64));
  const_bool_nodef(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> {
  const_bool_nodef(use_for_neg, false);
  const_bool_nodef(use_for_add, false);
  const_bool_nodef(use_for_sub, false);
  const_bool_nodef(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> {
  const_bool_nodef(use_for_neg, false);
  const_bool_nodef(use_for_add, false);
  const_bool_nodef(use_for_sub, false);
  const_bool_nodef(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> {
  const_bool_nodef(use_for_neg, false);
  const_bool_nodef(use_for_add, false);
  const_bool_nodef(use_for_sub, false);
  const_bool_nodef(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> {
  const_bool_nodef(use_for_neg, false);
  const_bool_nodef(use_for_add, false);
  const_bool_nodef(use_for_sub, false);
  const_bool_nodef(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 To_Policy, typename From_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<To_Policy, To_Policy>(to, l, dir);
}

template <typename To_Policy, typename From1_Policy, typename From2_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<To_Policy, To_Policy>(to, l, dir);
}

template <typename To_Policy, typename From1_Policy, typename From2_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<To_Policy, To_Policy>(to, l, dir);
}

template <typename To_Policy, typename From1_Policy, typename From2_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<To_Policy, To_Policy>(to, l, dir);
}

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

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

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

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

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

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

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

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

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

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

template <typename To_Policy, typename From1_Policy, typename From2_Policy, typename Type>
inline Result
idiv_signed_int(Type& to, const Type x, const Type y, Rounding_Dir dir) {
  if (CHECK_P(To_Policy::check_div_zero, y == 0))
    return assign_special<To_Policy>(to, V_DIV_ZERO, ROUND_IGNORE);
  if (To_Policy::check_overflow && y == -1)
    return neg_signed_int<To_Policy, From1_Policy>(to, x, dir);
  to = x / y;
  return V_EQ;
}

template <typename To_Policy, typename From1_Policy, typename From2_Policy, typename Type>
inline Result
idiv_unsigned_int(Type& to, const Type x, const Type y, Rounding_Dir) {
  if (CHECK_P(To_Policy::check_div_zero, y == 0))
    return assign_special<To_Policy>(to, V_DIV_ZERO, ROUND_IGNORE);
  to = x / y;
  return V_EQ;
}

template <typename To_Policy, typename From1_Policy, typename From2_Policy, typename Type>
inline Result
rem_signed_int(Type& to, const Type x, const Type y, Rounding_Dir) {
  if (CHECK_P(To_Policy::check_div_zero, y == 0))
    return assign_special<To_Policy>(to, V_MOD_ZERO, ROUND_IGNORE);
  to = x % y;
  return V_EQ;
}

template <typename To_Policy, typename From1_Policy, typename From2_Policy, typename Type>
inline Result
rem_unsigned_int(Type& to, const Type x, const Type y, Rounding_Dir) {
  if (CHECK_P(To_Policy::check_div_zero, y == 0))
    return assign_special<To_Policy>(to, V_MOD_ZERO, ROUND_IGNORE);
  to = x % y;
  return V_EQ;
}

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

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

template <typename To_Policy, typename From_Policy, typename Type>
inline Result
mul2exp_unsigned_int(Type& to, const Type x, int exp, Rounding_Dir dir) {
  if (exp < 0)
    return div2exp<To_Policy, From_Policy>(to, x, -exp, dir);
  if (!To_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<To_Policy>(to, dir);
  }
  if (x & (((static_cast<Type>(1) << exp) - 1) << (sizeof(Type) * 8 - exp)))
    return set_pos_overflow_int<To_Policy>(to, dir);
  Type n = x << exp;
  if (n > Extended_Int<To_Policy, Type>::max)
    return set_pos_overflow_int<To_Policy>(to, dir);
  to = n;
  return V_EQ;
}

template <typename To_Policy, typename From_Policy, typename Type>
inline Result
mul2exp_signed_int(Type& to, const Type x, int exp, Rounding_Dir dir) {
  if (exp < 0)
    return div2exp<To_Policy, From_Policy>(to, x, -exp, dir);
  if (!To_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<To_Policy>(to, dir);
    else if (x > 0)
      return set_pos_overflow_int<To_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<To_Policy>(to, dir);
    n = x << exp;
    if (n < Extended_Int<To_Policy, Type>::min)
      return set_neg_overflow_int<To_Policy>(to, dir);
  }
  else {
    if (x & mask)
      return set_pos_overflow_int<To_Policy>(to, dir);
    n = x << exp;
    if (n > Extended_Int<To_Policy, Type>::max)
      return set_pos_overflow_int<To_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 To_Policy, typename From_Policy, typename Type>
inline Result
sqrt_unsigned_int(Type& to, const Type from, Rounding_Dir dir) {
  Type rem;
  isqrtrem(to, rem, from);
  if (round_ignore(dir))
    return V_GE;
  if (rem == 0)
    return V_EQ;
  return round_gt_int<To_Policy>(to, dir);
}

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

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

template <typename To_Policy, typename From1_Policy, typename From2_Policy, typename Type>
inline Result
sub_mul_int(Type& to, const Type x, const Type y, Rounding_Dir dir) {
  Type z;
  Result r = mul<To_Policy, From1_Policy, From2_Policy>(z, x, y, dir);
  switch (r) {
  case V_NEG_OVERFLOW:
  case V_LT:
    if (to >= 0)
      return set_pos_overflow_int<To_Policy>(to, dir);
    return V_UNKNOWN_NEG_OVERFLOW;
  case V_POS_OVERFLOW:
  case V_GT:
    if (to <= 0)
      return set_neg_overflow_int<To_Policy>(to, dir);
    return V_UNKNOWN_POS_OVERFLOW;
  default:
    return sub<To_Policy, To_Policy, To_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 << static_cast<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;
}

PPL_SPECIALIZE_FLOOR(assign_signed_int_signed_int, signed char, signed char)
PPL_SPECIALIZE_FLOOR(assign_signed_int_signed_int, signed short, signed short)
PPL_SPECIALIZE_FLOOR(assign_signed_int_signed_int, signed int, signed int)
PPL_SPECIALIZE_FLOOR(assign_signed_int_signed_int, signed long, signed long)
PPL_SPECIALIZE_FLOOR(assign_signed_int_signed_int, signed long long, signed long long)
PPL_SPECIALIZE_FLOOR(assign_unsigned_int_unsigned_int, unsigned char, unsigned char)
PPL_SPECIALIZE_FLOOR(assign_unsigned_int_unsigned_int, unsigned short, unsigned short)
PPL_SPECIALIZE_FLOOR(assign_unsigned_int_unsigned_int, unsigned int, unsigned int)
PPL_SPECIALIZE_FLOOR(assign_unsigned_int_unsigned_int, unsigned long, unsigned long)
PPL_SPECIALIZE_FLOOR(assign_unsigned_int_unsigned_int, unsigned long long, unsigned long long)

PPL_SPECIALIZE_CEIL(assign_signed_int_signed_int, signed char, signed char)
PPL_SPECIALIZE_CEIL(assign_signed_int_signed_int, signed short, signed short)
PPL_SPECIALIZE_CEIL(assign_signed_int_signed_int, signed int, signed int)
PPL_SPECIALIZE_CEIL(assign_signed_int_signed_int, signed long, signed long)
PPL_SPECIALIZE_CEIL(assign_signed_int_signed_int, signed long long, signed long long)
PPL_SPECIALIZE_CEIL(assign_unsigned_int_unsigned_int, unsigned char, unsigned char)
PPL_SPECIALIZE_CEIL(assign_unsigned_int_unsigned_int, unsigned short, unsigned short)
PPL_SPECIALIZE_CEIL(assign_unsigned_int_unsigned_int, unsigned int, unsigned int)
PPL_SPECIALIZE_CEIL(assign_unsigned_int_unsigned_int, unsigned long, unsigned long)
PPL_SPECIALIZE_CEIL(assign_unsigned_int_unsigned_int, unsigned long long, unsigned long long)

PPL_SPECIALIZE_TRUNC(assign_signed_int_signed_int, signed char, signed char)
PPL_SPECIALIZE_TRUNC(assign_signed_int_signed_int, signed short, signed short)
PPL_SPECIALIZE_TRUNC(assign_signed_int_signed_int, signed int, signed int)
PPL_SPECIALIZE_TRUNC(assign_signed_int_signed_int, signed long, signed long)
PPL_SPECIALIZE_TRUNC(assign_signed_int_signed_int, signed long long, signed long long)
PPL_SPECIALIZE_TRUNC(assign_unsigned_int_unsigned_int, unsigned char, unsigned char)
PPL_SPECIALIZE_TRUNC(assign_unsigned_int_unsigned_int, unsigned short, unsigned short)
PPL_SPECIALIZE_TRUNC(assign_unsigned_int_unsigned_int, unsigned int, unsigned int)
PPL_SPECIALIZE_TRUNC(assign_unsigned_int_unsigned_int, unsigned long, unsigned long)
PPL_SPECIALIZE_TRUNC(assign_unsigned_int_unsigned_int, unsigned long long, unsigned long long)

PPL_SPECIALIZE_NEG(neg_signed_int, signed char, signed char)
PPL_SPECIALIZE_NEG(neg_signed_int, signed short, signed short)
PPL_SPECIALIZE_NEG(neg_signed_int, signed int, signed int)
PPL_SPECIALIZE_NEG(neg_signed_int, signed long, signed long)
PPL_SPECIALIZE_NEG(neg_signed_int, signed long long, signed long long)
PPL_SPECIALIZE_NEG(neg_unsigned_int, unsigned char, unsigned char)
PPL_SPECIALIZE_NEG(neg_unsigned_int, unsigned short, unsigned short)
PPL_SPECIALIZE_NEG(neg_unsigned_int, unsigned int, unsigned int)
PPL_SPECIALIZE_NEG(neg_unsigned_int, unsigned long, unsigned long)
PPL_SPECIALIZE_NEG(neg_unsigned_int, unsigned long long, unsigned long long)

PPL_SPECIALIZE_ADD(add_signed_int, signed char, signed char, signed char)
PPL_SPECIALIZE_ADD(add_signed_int, signed short, signed short, signed short)
PPL_SPECIALIZE_ADD(add_signed_int, signed int, signed int, signed int)
PPL_SPECIALIZE_ADD(add_signed_int, signed long, signed long, signed long)
PPL_SPECIALIZE_ADD(add_signed_int, signed long long, signed long long, signed long long)
PPL_SPECIALIZE_ADD(add_unsigned_int, unsigned char, unsigned char, unsigned char)
PPL_SPECIALIZE_ADD(add_unsigned_int, unsigned short, unsigned short, unsigned short)
PPL_SPECIALIZE_ADD(add_unsigned_int, unsigned int, unsigned int, unsigned int)
PPL_SPECIALIZE_ADD(add_unsigned_int, unsigned long, unsigned long, unsigned long)
PPL_SPECIALIZE_ADD(add_unsigned_int, unsigned long long, unsigned long long, unsigned long long)

PPL_SPECIALIZE_SUB(sub_signed_int, signed char, signed char, signed char)
PPL_SPECIALIZE_SUB(sub_signed_int, signed short, signed short, signed short)
PPL_SPECIALIZE_SUB(sub_signed_int, signed int, signed int, signed int)
PPL_SPECIALIZE_SUB(sub_signed_int, signed long, signed long, signed long)
PPL_SPECIALIZE_SUB(sub_signed_int, signed long long, signed long long, signed long long)
PPL_SPECIALIZE_SUB(sub_unsigned_int, unsigned char, unsigned char, unsigned char)
PPL_SPECIALIZE_SUB(sub_unsigned_int, unsigned short, unsigned short, unsigned short)
PPL_SPECIALIZE_SUB(sub_unsigned_int, unsigned int, unsigned int, unsigned int)
PPL_SPECIALIZE_SUB(sub_unsigned_int, unsigned long, unsigned long, unsigned long)
PPL_SPECIALIZE_SUB(sub_unsigned_int, unsigned long long, unsigned long long, unsigned long long)

PPL_SPECIALIZE_MUL(mul_signed_int, signed char, signed char, signed char)
PPL_SPECIALIZE_MUL(mul_signed_int, signed short, signed short, signed short)
PPL_SPECIALIZE_MUL(mul_signed_int, signed int, signed int, signed int)
PPL_SPECIALIZE_MUL(mul_signed_int, signed long, signed long, signed long)
PPL_SPECIALIZE_MUL(mul_signed_int, signed long long, signed long long, signed long long)
PPL_SPECIALIZE_MUL(mul_unsigned_int, unsigned char, unsigned char, unsigned char)
PPL_SPECIALIZE_MUL(mul_unsigned_int, unsigned short, unsigned short, unsigned short)
PPL_SPECIALIZE_MUL(mul_unsigned_int, unsigned int, unsigned int, unsigned int)
PPL_SPECIALIZE_MUL(mul_unsigned_int, unsigned long, unsigned long, unsigned long)
PPL_SPECIALIZE_MUL(mul_unsigned_int, unsigned long long, unsigned long long, unsigned long long)

PPL_SPECIALIZE_DIV(div_signed_int, signed char, signed char, signed char)
PPL_SPECIALIZE_DIV(div_signed_int, signed short, signed short, signed short)
PPL_SPECIALIZE_DIV(div_signed_int, signed int, signed int, signed int)
PPL_SPECIALIZE_DIV(div_signed_int, signed long, signed long, signed long)
PPL_SPECIALIZE_DIV(div_signed_int, signed long long, signed long long, signed long long)
PPL_SPECIALIZE_DIV(div_unsigned_int, unsigned char, unsigned char, unsigned char)
PPL_SPECIALIZE_DIV(div_unsigned_int, unsigned short, unsigned short, unsigned short)
PPL_SPECIALIZE_DIV(div_unsigned_int, unsigned int, unsigned int, unsigned int)
PPL_SPECIALIZE_DIV(div_unsigned_int, unsigned long, unsigned long, unsigned long)
PPL_SPECIALIZE_DIV(div_unsigned_int, unsigned long long, unsigned long long, unsigned long long)

PPL_SPECIALIZE_IDIV(idiv_signed_int, signed char, signed char, signed char)
PPL_SPECIALIZE_IDIV(idiv_signed_int, signed short, signed short, signed short)
PPL_SPECIALIZE_IDIV(idiv_signed_int, signed int, signed int, signed int)
PPL_SPECIALIZE_IDIV(idiv_signed_int, signed long, signed long, signed long)
PPL_SPECIALIZE_IDIV(idiv_signed_int, signed long long, signed long long, signed long long)
PPL_SPECIALIZE_IDIV(idiv_unsigned_int, unsigned char, unsigned char, unsigned char)
PPL_SPECIALIZE_IDIV(idiv_unsigned_int, unsigned short, unsigned short, unsigned short)
PPL_SPECIALIZE_IDIV(idiv_unsigned_int, unsigned int, unsigned int, unsigned int)
PPL_SPECIALIZE_IDIV(idiv_unsigned_int, unsigned long, unsigned long, unsigned long)
PPL_SPECIALIZE_IDIV(idiv_unsigned_int, unsigned long long, unsigned long long, unsigned long long)

PPL_SPECIALIZE_REM(rem_signed_int, signed char, signed char, signed char)
PPL_SPECIALIZE_REM(rem_signed_int, signed short, signed short, signed short)
PPL_SPECIALIZE_REM(rem_signed_int, signed int, signed int, signed int)
PPL_SPECIALIZE_REM(rem_signed_int, signed long, signed long, signed long)
PPL_SPECIALIZE_REM(rem_signed_int, signed long long, signed long long, signed long long)
PPL_SPECIALIZE_REM(rem_unsigned_int, unsigned char, unsigned char, unsigned char)
PPL_SPECIALIZE_REM(rem_unsigned_int, unsigned short, unsigned short, unsigned short)
PPL_SPECIALIZE_REM(rem_unsigned_int, unsigned int, unsigned int, unsigned int)
PPL_SPECIALIZE_REM(rem_unsigned_int, unsigned long, unsigned long, unsigned long)
PPL_SPECIALIZE_REM(rem_unsigned_int, unsigned long long, unsigned long long, unsigned long long)

PPL_SPECIALIZE_MUL2EXP(mul2exp_signed_int, signed char, signed char)
PPL_SPECIALIZE_MUL2EXP(mul2exp_signed_int, signed short, signed short)
PPL_SPECIALIZE_MUL2EXP(mul2exp_signed_int, signed int, signed int)
PPL_SPECIALIZE_MUL2EXP(mul2exp_signed_int, signed long, signed long)
PPL_SPECIALIZE_MUL2EXP(mul2exp_signed_int, signed long long, signed long long)
PPL_SPECIALIZE_MUL2EXP(mul2exp_unsigned_int, unsigned char, unsigned char)
PPL_SPECIALIZE_MUL2EXP(mul2exp_unsigned_int, unsigned short, unsigned short)
PPL_SPECIALIZE_MUL2EXP(mul2exp_unsigned_int, unsigned int, unsigned int)
PPL_SPECIALIZE_MUL2EXP(mul2exp_unsigned_int, unsigned long, unsigned long)
PPL_SPECIALIZE_MUL2EXP(mul2exp_unsigned_int, unsigned long long, unsigned long long)

PPL_SPECIALIZE_DIV2EXP(div2exp_signed_int, signed char, signed char)
PPL_SPECIALIZE_DIV2EXP(div2exp_signed_int, signed short, signed short)
PPL_SPECIALIZE_DIV2EXP(div2exp_signed_int, signed int, signed int)
PPL_SPECIALIZE_DIV2EXP(div2exp_signed_int, signed long, signed long)
PPL_SPECIALIZE_DIV2EXP(div2exp_signed_int, signed long long, signed long long)
PPL_SPECIALIZE_DIV2EXP(div2exp_unsigned_int, unsigned char, unsigned char)
PPL_SPECIALIZE_DIV2EXP(div2exp_unsigned_int, unsigned short, unsigned short)
PPL_SPECIALIZE_DIV2EXP(div2exp_unsigned_int, unsigned int, unsigned int)
PPL_SPECIALIZE_DIV2EXP(div2exp_unsigned_int, unsigned long, unsigned long)
PPL_SPECIALIZE_DIV2EXP(div2exp_unsigned_int, unsigned long long, unsigned long long)

PPL_SPECIALIZE_SQRT(sqrt_signed_int, signed char, signed char)
PPL_SPECIALIZE_SQRT(sqrt_signed_int, signed short, signed short)
PPL_SPECIALIZE_SQRT(sqrt_signed_int, signed int, signed int)
PPL_SPECIALIZE_SQRT(sqrt_signed_int, signed long, signed long)
PPL_SPECIALIZE_SQRT(sqrt_signed_int, signed long long, signed long long)
PPL_SPECIALIZE_SQRT(sqrt_unsigned_int, unsigned char, unsigned char)
PPL_SPECIALIZE_SQRT(sqrt_unsigned_int, unsigned short, unsigned short)
PPL_SPECIALIZE_SQRT(sqrt_unsigned_int, unsigned int, unsigned int)
PPL_SPECIALIZE_SQRT(sqrt_unsigned_int, unsigned long, unsigned long)
PPL_SPECIALIZE_SQRT(sqrt_unsigned_int, unsigned long long, unsigned long long)

PPL_SPECIALIZE_ABS(abs_generic, signed char, signed char)
PPL_SPECIALIZE_ABS(abs_generic, signed short, signed short)
PPL_SPECIALIZE_ABS(abs_generic, signed int, signed int)
PPL_SPECIALIZE_ABS(abs_generic, signed long, signed long)
PPL_SPECIALIZE_ABS(abs_generic, signed long long, signed long long)
PPL_SPECIALIZE_ABS(assign_unsigned_int_unsigned_int, unsigned char, unsigned char)
PPL_SPECIALIZE_ABS(assign_unsigned_int_unsigned_int, unsigned short, unsigned short)
PPL_SPECIALIZE_ABS(assign_unsigned_int_unsigned_int, unsigned int, unsigned int)
PPL_SPECIALIZE_ABS(assign_unsigned_int_unsigned_int, unsigned long, unsigned long)
PPL_SPECIALIZE_ABS(assign_unsigned_int_unsigned_int, unsigned long long, unsigned long long)

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

PPL_SPECIALIZE_GCDEXT(gcdext_exact, signed char, signed char, signed char, signed char, signed char)
PPL_SPECIALIZE_GCDEXT(gcdext_exact, signed short, signed short, signed short, signed short, signed short)
PPL_SPECIALIZE_GCDEXT(gcdext_exact, signed int, signed int, signed int, signed int, signed int)
PPL_SPECIALIZE_GCDEXT(gcdext_exact, signed long, signed long, signed long, signed long, signed long)
PPL_SPECIALIZE_GCDEXT(gcdext_exact, signed long long, signed long long, signed long long, signed long long, signed long long)
PPL_SPECIALIZE_GCDEXT(gcdext_exact, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char)
PPL_SPECIALIZE_GCDEXT(gcdext_exact, unsigned short, unsigned short, unsigned short, unsigned short, unsigned short)
PPL_SPECIALIZE_GCDEXT(gcdext_exact, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int)
PPL_SPECIALIZE_GCDEXT(gcdext_exact, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long)
PPL_SPECIALIZE_GCDEXT(gcdext_exact, unsigned long long, unsigned long long, unsigned long long, unsigned long long, unsigned long long)

PPL_SPECIALIZE_LCM(lcm_gcd_exact, signed char, signed char, signed char)
PPL_SPECIALIZE_LCM(lcm_gcd_exact, signed short, signed short, signed short)
PPL_SPECIALIZE_LCM(lcm_gcd_exact, signed int, signed int, signed int)
PPL_SPECIALIZE_LCM(lcm_gcd_exact, signed long, signed long, signed long)
PPL_SPECIALIZE_LCM(lcm_gcd_exact, signed long long, signed long long, signed long long)
PPL_SPECIALIZE_LCM(lcm_gcd_exact, unsigned char, unsigned char, unsigned char)
PPL_SPECIALIZE_LCM(lcm_gcd_exact, unsigned short, unsigned short, unsigned short)
PPL_SPECIALIZE_LCM(lcm_gcd_exact, unsigned int, unsigned int, unsigned int)
PPL_SPECIALIZE_LCM(lcm_gcd_exact, unsigned long, unsigned long, unsigned long)
PPL_SPECIALIZE_LCM(lcm_gcd_exact, unsigned long long, unsigned long long, unsigned long long)

PPL_SPECIALIZE_SGN(sgn_generic, signed char)
PPL_SPECIALIZE_SGN(sgn_generic, signed short)
PPL_SPECIALIZE_SGN(sgn_generic, signed int)
PPL_SPECIALIZE_SGN(sgn_generic, signed long)
PPL_SPECIALIZE_SGN(sgn_generic, signed long long)
PPL_SPECIALIZE_SGN(sgn_generic, unsigned char)
PPL_SPECIALIZE_SGN(sgn_generic, unsigned short)
PPL_SPECIALIZE_SGN(sgn_generic, unsigned int)
PPL_SPECIALIZE_SGN(sgn_generic, unsigned long)
PPL_SPECIALIZE_SGN(sgn_generic, unsigned long long)

PPL_SPECIALIZE_CMP(cmp_generic, signed char, signed char)
PPL_SPECIALIZE_CMP(cmp_generic, signed short, signed short)
PPL_SPECIALIZE_CMP(cmp_generic, signed int, signed int)
PPL_SPECIALIZE_CMP(cmp_generic, signed long, signed long)
PPL_SPECIALIZE_CMP(cmp_generic, signed long long, signed long long)
PPL_SPECIALIZE_CMP(cmp_generic, unsigned char, unsigned char)
PPL_SPECIALIZE_CMP(cmp_generic, unsigned short, unsigned short)
PPL_SPECIALIZE_CMP(cmp_generic, unsigned int, unsigned int)
PPL_SPECIALIZE_CMP(cmp_generic, unsigned long, unsigned long)
PPL_SPECIALIZE_CMP(cmp_generic, unsigned long long, unsigned long long)

PPL_SPECIALIZE_ADD_MUL(add_mul_int, signed char, signed char, signed char)
PPL_SPECIALIZE_ADD_MUL(add_mul_int, signed short, signed short, signed short)
PPL_SPECIALIZE_ADD_MUL(add_mul_int, signed int, signed int, signed int)
PPL_SPECIALIZE_ADD_MUL(add_mul_int, signed long, signed long, signed long)
PPL_SPECIALIZE_ADD_MUL(add_mul_int, signed long long, signed long long, signed long long)
PPL_SPECIALIZE_ADD_MUL(add_mul_int, unsigned char, unsigned char, unsigned char)
PPL_SPECIALIZE_ADD_MUL(add_mul_int, unsigned short, unsigned short, unsigned short)
PPL_SPECIALIZE_ADD_MUL(add_mul_int, unsigned int, unsigned int, unsigned int)
PPL_SPECIALIZE_ADD_MUL(add_mul_int, unsigned long, unsigned long, unsigned long)
PPL_SPECIALIZE_ADD_MUL(add_mul_int, unsigned long long, unsigned long long, unsigned long long)

PPL_SPECIALIZE_SUB_MUL(sub_mul_int, signed char, signed char, signed char)
PPL_SPECIALIZE_SUB_MUL(sub_mul_int, signed short, signed short, signed short)
PPL_SPECIALIZE_SUB_MUL(sub_mul_int, signed int, signed int, signed int)
PPL_SPECIALIZE_SUB_MUL(sub_mul_int, signed long, signed long, signed long)
PPL_SPECIALIZE_SUB_MUL(sub_mul_int, signed long long, signed long long, signed long long)
PPL_SPECIALIZE_SUB_MUL(sub_mul_int, unsigned char, unsigned char, unsigned char)
PPL_SPECIALIZE_SUB_MUL(sub_mul_int, unsigned short, unsigned short, unsigned short)
PPL_SPECIALIZE_SUB_MUL(sub_mul_int, unsigned int, unsigned int, unsigned int)
PPL_SPECIALIZE_SUB_MUL(sub_mul_int, unsigned long, unsigned long, unsigned long)
PPL_SPECIALIZE_SUB_MUL(sub_mul_int, unsigned long long, unsigned long long, unsigned long long)

PPL_SPECIALIZE_INPUT(input_generic, signed char)
PPL_SPECIALIZE_INPUT(input_generic, signed short)
PPL_SPECIALIZE_INPUT(input_generic, signed int)
PPL_SPECIALIZE_INPUT(input_generic, signed long)
PPL_SPECIALIZE_INPUT(input_generic, signed long long)
PPL_SPECIALIZE_INPUT(input_generic, unsigned char)
PPL_SPECIALIZE_INPUT(input_generic, unsigned short)
PPL_SPECIALIZE_INPUT(input_generic, unsigned int)
PPL_SPECIALIZE_INPUT(input_generic, unsigned long)
PPL_SPECIALIZE_INPUT(input_generic, unsigned long long)

PPL_SPECIALIZE_OUTPUT(output_char, signed char)
PPL_SPECIALIZE_OUTPUT(output_int, signed short)
PPL_SPECIALIZE_OUTPUT(output_int, signed int)
PPL_SPECIALIZE_OUTPUT(output_int, signed long)
PPL_SPECIALIZE_OUTPUT(output_int, signed long long)
PPL_SPECIALIZE_OUTPUT(output_char, unsigned char)
PPL_SPECIALIZE_OUTPUT(output_int, unsigned short)
PPL_SPECIALIZE_OUTPUT(output_int, unsigned int)
PPL_SPECIALIZE_OUTPUT(output_int, unsigned long)
PPL_SPECIALIZE_OUTPUT(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/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 PPL_HAVE_DECL_FMAF && defined(FP_FAST_FMAF) \
  && !defined(__alpha) && !defined(__FreeBSD__)
  return ::fmaf(x, y, z);
#else
  return x*y + z;
#endif
}

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

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

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

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

#if PPL_HAVE_DECL_RINTL
inline long double
rint(long double x) {
  return ::rintl(x);
}
#elif !PPL_CXX_PROVIDES_PROPER_LONG_DOUBLE
// If proper long doubles are not provided, this is most likely
// because long double and double are the same type: use rint().
inline long double
rint(long double x) {
  return ::rint(x);
}
#elif defined(__i386__) && (defined(__GNUC__) || defined(__INTEL_COMPILER))
// On Cygwin, we have proper long doubles but rintl() is not defined:
// luckily, one machine instruction is enough to save the day.
inline long double
rint(long double x) {
  long double i;
  __asm__ ("frndint" : "=t" (i) : "0" (x));
  return i;
}
#endif

inline bool
fpu_direct_rounding(Rounding_Dir dir) {
  return round_direct(dir) || round_ignore(dir);
}

inline bool
fpu_inverse_rounding(Rounding_Dir dir) {
  return round_inverse(dir);
}

// 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 void
limit_precision(const float& v) {
  cc_flush(v);
}

inline void
limit_precision(const double& v) {
  cc_flush(v);
}

inline void
limit_precision(const long double&) {
}

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) && CHECK_P(Policy::has_nan, f.u.binary.is_nan()))
    return VC_NAN;
  if (inf) {
    int i = CHECK_P(Policy::has_infinity, 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 CHECK_P(Policy::has_nan, f.u.binary.is_nan());
}

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

template <typename Policy, typename T>
inline bool
is_pinf_float(const T v) {
  return is_inf_float<Policy>(v) > 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
assign_special_float(T& v, Result r, Rounding_Dir) {
  switch (classify(r)) {
  case VC_MINUS_INFINITY:
    v = -HUGE_VAL;
    break;
  case VC_PLUS_INFINITY:
    v = HUGE_VAL;
    break;
  case VC_NAN:
    v = PPL_NAN;
    return r;
  default:
    break;
  }
  return V_EQ;
}

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 (round_down(dir)) {
    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 (round_up(dir)) {
    succ_float(to);
    return V_LT;
  }
  return V_GT;
}


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

template <typename Policy>
inline Result
result_relation(Rounding_Dir dir) {
  if (Policy::fpu_check_inexact && round_fpu_check_inexact(dir)) {
    switch (fpu_check_inexact()) {
    case 0:
      return V_EQ;
    case -1:
      goto unknown;
    case 1:
      break;
    }
    switch (round_dir(dir)) {
    case ROUND_DOWN:
      return V_GT;
    case ROUND_UP:
      return V_LT;
    default:
      return V_NE;
    }
  }
  else {
  unknown:
    switch (round_dir(dir)) {
    case ROUND_DOWN:
      return V_GE;
    case ROUND_UP:
      return V_LE;
    default:
      return V_LGE;
    }
  }
}

template <typename To_Policy, typename From_Policy, typename To, typename From>
inline Result
assign_float_float_exact(To& to, const From from, Rounding_Dir) {
  if (To_Policy::check_nan_result && is_nan<From_Policy>(from))
    return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
  to = from;
  return V_EQ;
}

template <typename To_Policy, typename From_Policy, typename To, typename From>
inline Result
assign_float_float_inexact(To& to, const From from, Rounding_Dir dir) {
  if (To_Policy::check_nan_result && is_nan<From_Policy>(from))
    return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
  prepare_inexact<To_Policy>(dir);
  if (fpu_direct_rounding(dir))
    to = from;
  else if (fpu_inverse_rounding(dir)) {
    From tmp = -from;
    to = tmp;
    limit_precision(to);
    to = -to;
  }
  else {
    fpu_rounding_control_word_type old
      = fpu_save_rounding_direction(round_fpu_dir(dir));
    limit_precision(from);
    to = from;
    limit_precision(to);
    fpu_restore_rounding_direction(old);
  }
  return result_relation<To_Policy>(dir);
}

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

template <typename To_Policy, typename From_Policy, typename Type>
inline Result
floor_float(Type& to, const Type from, Rounding_Dir) {
  if (To_Policy::check_nan_result && is_nan<From_Policy>(from))
    return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
  if (fpu_direct_rounding(ROUND_DOWN))
    to = rint(from);
  else if (fpu_inverse_rounding(ROUND_DOWN)) {
    to = rint(-from);
    limit_precision(to);
    to = -to;
  }
  else {
    fpu_rounding_control_word_type old
      = fpu_save_rounding_direction(round_fpu_dir(ROUND_DOWN));
    limit_precision(from);
    to = rint(from);
    limit_precision(to);
    fpu_restore_rounding_direction(old);
  }
  return V_EQ;
}

template <typename To_Policy, typename From_Policy, typename Type>
inline Result
ceil_float(Type& to, const Type from, Rounding_Dir) {
  if (To_Policy::check_nan_result && is_nan<From_Policy>(from))
    return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
  if (fpu_direct_rounding(ROUND_UP))
    to = rint(from);
  else if (fpu_inverse_rounding(ROUND_UP)) {
    to = rint(-from);
    limit_precision(to);
    to = -to;
  }
  else {
    fpu_rounding_control_word_type old
      = fpu_save_rounding_direction(round_fpu_dir(ROUND_UP));
    limit_precision(from);
    to = rint(from);
    limit_precision(to);
    fpu_restore_rounding_direction(old);
  }
  return V_EQ;
}

template <typename To_Policy, typename From_Policy, typename Type>
inline Result
trunc_float(Type& to, const Type from, Rounding_Dir dir) {
  if (To_Policy::check_nan_result && is_nan<From_Policy>(from))
    return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
  if (from >= 0)
    return floor<To_Policy, From_Policy>(to, from, dir);
  else
    return ceil<To_Policy, From_Policy>(to, from, dir);
}

template <typename To_Policy, typename From_Policy, typename Type>
inline Result
neg_float(Type& to, const Type from, Rounding_Dir) {
  if (To_Policy::check_nan_result && is_nan<From_Policy>(from))
    return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
  to = -from;
  return V_EQ;
}

template <typename To_Policy, typename From1_Policy, typename From2_Policy,
	  typename Type>
inline Result
add_float(Type& to, const Type x, const Type y, Rounding_Dir dir) {
  if (To_Policy::check_inf_add_inf
      && is_inf_float<From1_Policy>(x) && x == -y)
    return assign_special<To_Policy>(to, V_INF_ADD_INF, ROUND_IGNORE);
  prepare_inexact<To_Policy>(dir);
  if (fpu_direct_rounding(dir))
    to = x + y;
  else if (fpu_inverse_rounding(dir)) {
    to = -x - y;
    limit_precision(to);
    to = -to;
  }
  else {
    fpu_rounding_control_word_type old
      = fpu_save_rounding_direction(round_fpu_dir(dir));
    limit_precision(x);
    limit_precision(y);
    to = x + y;
    limit_precision(to);
    fpu_restore_rounding_direction(old);
  }
  if (To_Policy::check_nan_result && is_nan<To_Policy>(to))
    return VC_NAN;
  return result_relation<To_Policy>(dir);
}

template <typename To_Policy, typename From1_Policy, typename From2_Policy,
	  typename Type>
inline Result
sub_float(Type& to, const Type x, const Type y, Rounding_Dir dir) {
  if (To_Policy::check_inf_sub_inf
      && is_inf_float<From1_Policy>(x) && x == y)
    return assign_special<To_Policy>(to, V_INF_SUB_INF, ROUND_IGNORE);
  prepare_inexact<To_Policy>(dir);
  if (fpu_direct_rounding(dir))
    to = x - y;
  else if (fpu_inverse_rounding(dir)) {
    to = y - x;
    limit_precision(to);
    to = -to;
  }
  else {
    fpu_rounding_control_word_type old
      = fpu_save_rounding_direction(round_fpu_dir(dir));
    limit_precision(x);
    limit_precision(y);
    to = x - y;
    limit_precision(to);
    fpu_restore_rounding_direction(old);
  }
  if (To_Policy::check_nan_result && is_nan<To_Policy>(to))
    return VC_NAN;
  return result_relation<To_Policy>(dir);
}

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

template <typename To_Policy, typename From1_Policy, typename From2_Policy,
	  typename Type>
inline Result
div_float(Type& to, const Type x, const Type y, Rounding_Dir dir) {
  if (To_Policy::check_inf_div_inf
      && is_inf_float<From1_Policy>(x) && is_inf_float<From2_Policy>(y))
    return assign_special<To_Policy>(to, V_INF_DIV_INF, ROUND_IGNORE);
  if (To_Policy::check_div_zero && y == 0)
    return assign_special<To_Policy>(to, V_DIV_ZERO, ROUND_IGNORE);
  prepare_inexact<To_Policy>(dir);
  if (fpu_direct_rounding(dir))
    to = x / y;
  else if (fpu_inverse_rounding(dir)) {
    to = x / -y;
    limit_precision(to);
    to = -to;
  }
  else {
    fpu_rounding_control_word_type old
      = fpu_save_rounding_direction(round_fpu_dir(dir));
    limit_precision(x);
    limit_precision(y);
    to = x / y;
    limit_precision(to);
    fpu_restore_rounding_direction(old);
  }
  if (To_Policy::check_nan_result && is_nan<To_Policy>(to))
    return VC_NAN;
  return result_relation<To_Policy>(dir);
}

template <typename To_Policy, typename From1_Policy, typename From2_Policy,
	  typename Type>
inline Result
idiv_float(Type& to, const Type x, const Type y, Rounding_Dir dir) {
  Type temp;
  // The inexact check is useless
  dir = round_dir(dir);
  Result r = div<To_Policy, From1_Policy, From2_Policy>(temp, x, y, dir);
  if (is_special(r)) {
    to = temp;
    return r;
  }
  Result r1 = trunc<To_Policy, To_Policy>(to, temp, ROUND_NOT_NEEDED);
  assert(r1 == V_EQ);
  if (r == V_EQ || to != temp)
    return r1;
  // FIXME: Prove that it's impossibile to return a strict relation
  return dir == ROUND_UP ? V_LE : V_GE;
}

template <typename To_Policy, typename From1_Policy, typename From2_Policy,
	  typename Type>
inline Result
rem_float(Type& to, const Type x, const Type y, Rounding_Dir) {
  if (To_Policy::check_inf_mod && is_inf_float<From1_Policy>(x))
    return assign_special<To_Policy>(to, V_INF_MOD, ROUND_IGNORE);
  if (To_Policy::check_div_zero && y == 0)
    return assign_special<To_Policy>(to, V_MOD_ZERO, ROUND_IGNORE);
  to = std::fmod(x, y);
  if (To_Policy::check_nan_result && is_nan<To_Policy>(to))
    return VC_NAN;
  return V_EQ;
}

struct Float_2exp {
  const_bool_nodef(has_nan, false);
  const_bool_nodef(has_infinity, false);
};

template <typename To_Policy, typename From_Policy, typename Type>
inline Result
mul2exp_float(Type& to, const Type x, int exp, Rounding_Dir dir) {
  if (To_Policy::check_nan_result && is_nan<From_Policy>(x))
    return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
  if (exp < 0)
    return div2exp<To_Policy, From_Policy>(to, x, -exp, dir);
  assert(static_cast<unsigned int>(exp) < sizeof(unsigned long long) * 8);
  return mul<To_Policy, From_Policy, Float_2exp>(to, x, static_cast<Type>(1ULL << exp), dir);
}

template <typename To_Policy, typename From_Policy, typename Type>
inline Result
div2exp_float(Type& to, const Type x, int exp, Rounding_Dir dir) {
  if (To_Policy::check_nan_result && is_nan<From_Policy>(x))
    return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
  if (exp < 0)
    return mul2exp<To_Policy, From_Policy>(to, x, -exp, dir);
  assert(static_cast<unsigned int>(exp) < sizeof(unsigned long long) * 8);
  return div<To_Policy, From_Policy, Float_2exp>(to, x, static_cast<Type>(1ULL << exp), dir);
}

template <typename To_Policy, typename From_Policy, typename Type>
inline Result
abs_float(Type& to, const Type from, Rounding_Dir) {
  if (To_Policy::check_nan_result && is_nan<From_Policy>(from))
    return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
  to = std::abs(from);
  return V_EQ;
}

template <typename To_Policy, typename From_Policy, typename Type>
inline Result
sqrt_float(Type& to, const Type from, Rounding_Dir dir) {
  if (To_Policy::check_nan_result && is_nan<From_Policy>(from))
    return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
  if (To_Policy::check_sqrt_neg && from < 0)
    return assign_special<To_Policy>(to, V_SQRT_NEG, ROUND_IGNORE);
  prepare_inexact<To_Policy>(dir);
  if (fpu_direct_rounding(dir))
    to = std::sqrt(from);
  else {
    fpu_rounding_control_word_type old
      = fpu_save_rounding_direction(round_fpu_dir(dir));
    limit_precision(from);
    to = std::sqrt(from);
    limit_precision(to);
    fpu_restore_rounding_direction(old);
  }
  return result_relation<To_Policy>(dir);
}

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

template <typename Policy1, typename Policy2, 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 To_Policy, typename From_Policy, typename To, typename From>
inline Result
assign_float_int_inexact(To& to, const From from, Rounding_Dir dir) {
  prepare_inexact<To_Policy>(dir);
  if (fpu_direct_rounding(dir))
    to = from;
  else {
    fpu_rounding_control_word_type old
      = fpu_save_rounding_direction(round_fpu_dir(dir));
    to = from;
    limit_precision(to);
    fpu_restore_rounding_direction(old);
  }
  return result_relation<To_Policy>(dir);
}

template <typename To_Policy, typename From_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<To_Policy, From_Policy>(to, from, dir);
  else
    return assign_exact<To_Policy, From_Policy>(to, from, dir);
}

template <typename Policy, typename T>
inline Result
set_neg_overflow_float(T& to, Rounding_Dir dir) {
  switch (round_dir(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 (round_dir(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 To_Policy, typename From_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 > static_cast<size_t>(Float<T>::Binary::EXPONENT_MAX)) {
    if (sign < 0)
      return set_neg_overflow_float<To_Policy>(to, dir);
    else
      return set_pos_overflow_float<To_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<To_Policy>(to, dir);
    else
      return round_gt_float<To_Policy>(to, dir);
  }
  return V_EQ;
}

template <typename To_Policy, typename From_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<To_Policy, From_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<To_Policy>(to, dir);
    else
      return round_gt_float<To_Policy>(to, dir);
  }
  if (exponent > static_cast<signed int>(Float<T>::Binary::EXPONENT_MAX + 1)) {
  overflow:
    if (sign < 0)
      return set_neg_overflow_float<To_Policy>(to, dir);
    else
      return set_pos_overflow_float<To_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 > static_cast<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 To_Policy, typename From1_Policy, typename From2_Policy,
	  typename Type>
inline Result
add_mul_float(Type& to, const Type x, const Type y, Rounding_Dir dir) {
  if (To_Policy::check_inf_mul_zero
      && ((x == 0 && is_inf_float<From2_Policy>(y)) ||
	  (y == 0 && is_inf_float<From1_Policy>(x))))
    return assign_special<To_Policy>(to, V_INF_MUL_ZERO, ROUND_IGNORE);
  // FIXME: missing check_inf_add_inf
  prepare_inexact<To_Policy>(dir);
  if (fpu_direct_rounding(dir))
    to = fma(x, y, to);
  else if (fpu_inverse_rounding(dir)) {
    to = fma(-x, y, -to);
    limit_precision(to);
    to = -to;
  }
  else {
    fpu_rounding_control_word_type old
      = fpu_save_rounding_direction(round_fpu_dir(dir));
    limit_precision(x);
    limit_precision(y);
    limit_precision(to);
    to = fma(x, y, to);
    limit_precision(to);
    fpu_restore_rounding_direction(old);
  }
  if (To_Policy::check_nan_result && is_nan<To_Policy>(to))
    return VC_NAN;
  return result_relation<To_Policy>(dir);
}

template <typename To_Policy, typename From1_Policy, typename From2_Policy, typename Type>
inline Result
sub_mul_float(Type& to, const Type x, const Type y, Rounding_Dir dir) {
  if (To_Policy::check_inf_mul_zero
      && ((x == 0 && is_inf_float<From2_Policy>(y)) ||
	  (y == 0 && is_inf_float<From1_Policy>(x))))
    return assign_special<To_Policy>(to, V_INF_MUL_ZERO, ROUND_IGNORE);
  // FIXME: missing check_inf_add_inf
  prepare_inexact<To_Policy>(dir);
  if (fpu_direct_rounding(dir))
    to = fma(x, -y, to);
  else if (fpu_inverse_rounding(dir)) {
    to = fma(x, y, -to);
    limit_precision(to);
    to = -to;
  }
  else {
    fpu_rounding_control_word_type old
      = fpu_save_rounding_direction(round_fpu_dir(dir));
    limit_precision(x);
    limit_precision(y);
    limit_precision(to);
    to = fma(x, -y, to);
    limit_precision(to);
    fpu_restore_rounding_direction(old);
  }
  if (To_Policy::check_nan_result && is_nan<To_Policy>(to))
    return VC_NAN;
  return result_relation<To_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);
    // FIXME: here correctness depends on the behavior of the standard
    // output operator which, in turn, may depend on the behavior
    // of printf().  The C99 standard, 7.19.16.1#13, does not give
    // enough guarantees.  We could not find something similar
    // in the C++ standard, so there is a concrete danger here.
    os << from;
    os.precision(old_precision);
  }
  return V_EQ;
}

#if PPL_SUPPORTED_FLOAT
PPL_SPECIALIZE_ASSIGN(assign_float_float_exact, float, float)
#if PPL_SUPPORTED_DOUBLE
PPL_SPECIALIZE_ASSIGN(assign_float_float, float, double)
PPL_SPECIALIZE_ASSIGN(assign_float_float_exact, double, float)
#endif
#if PPL_SUPPORTED_LONG_DOUBLE
PPL_SPECIALIZE_ASSIGN(assign_float_float, float, long double)
PPL_SPECIALIZE_ASSIGN(assign_float_float_exact, long double, float)
#endif
#endif

#if PPL_SUPPORTED_DOUBLE
PPL_SPECIALIZE_ASSIGN(assign_float_float_exact, double, double)
#if PPL_SUPPORTED_LONG_DOUBLE
PPL_SPECIALIZE_ASSIGN(assign_float_float, double, long double)
PPL_SPECIALIZE_ASSIGN(assign_float_float_exact, long double, double)
#endif
#endif

#if PPL_SUPPORTED_LONG_DOUBLE
PPL_SPECIALIZE_ASSIGN(assign_float_float_exact, long double, long double)
#endif

#if PPL_SUPPORTED_FLOAT
PPL_SPECIALIZE_CLASSIFY(classify_float, float)
PPL_SPECIALIZE_IS_NAN(is_nan_float, float)
PPL_SPECIALIZE_IS_MINF(is_minf_float, float)
PPL_SPECIALIZE_IS_PINF(is_pinf_float, float)
PPL_SPECIALIZE_ASSIGN_SPECIAL(assign_special_float, float)
PPL_SPECIALIZE_ASSIGN(assign_float_int, float, signed char)
PPL_SPECIALIZE_ASSIGN(assign_float_int, float, signed short)
PPL_SPECIALIZE_ASSIGN(assign_float_int, float, signed int)
PPL_SPECIALIZE_ASSIGN(assign_float_int, float, signed long)
PPL_SPECIALIZE_ASSIGN(assign_float_int, float, signed long long)
PPL_SPECIALIZE_ASSIGN(assign_float_int, float, unsigned char)
PPL_SPECIALIZE_ASSIGN(assign_float_int, float, unsigned short)
PPL_SPECIALIZE_ASSIGN(assign_float_int, float, unsigned int)
PPL_SPECIALIZE_ASSIGN(assign_float_int, float, unsigned long)
PPL_SPECIALIZE_ASSIGN(assign_float_int, float, unsigned long long)
PPL_SPECIALIZE_ASSIGN(assign_float_mpz, float, mpz_class)
PPL_SPECIALIZE_ASSIGN(assign_float_mpq, float, mpq_class)
PPL_SPECIALIZE_COPY(copy_generic, float)
PPL_SPECIALIZE_IS_INT(is_int_float, float)
PPL_SPECIALIZE_FLOOR(floor_float, float, float)
PPL_SPECIALIZE_CEIL(ceil_float, float, float)
PPL_SPECIALIZE_TRUNC(trunc_float, float, float)
PPL_SPECIALIZE_NEG(neg_float, float, float)
PPL_SPECIALIZE_ABS(abs_float, float, float)
PPL_SPECIALIZE_ADD(add_float, float, float, float)
PPL_SPECIALIZE_SUB(sub_float, float, float, float)
PPL_SPECIALIZE_MUL(mul_float, float, float, float)
PPL_SPECIALIZE_DIV(div_float, float, float, float)
PPL_SPECIALIZE_REM(rem_float, float, float, float)
PPL_SPECIALIZE_MUL2EXP(mul2exp_float, float, float)
PPL_SPECIALIZE_DIV2EXP(div2exp_float, float, float)
PPL_SPECIALIZE_SQRT(sqrt_float, float, float)
PPL_SPECIALIZE_GCD(gcd_exact, float, float, float)
PPL_SPECIALIZE_GCDEXT(gcdext_exact, float, float, float, float, float)
PPL_SPECIALIZE_LCM(lcm_gcd_exact, float, float, float)
PPL_SPECIALIZE_SGN(sgn_float, float)
PPL_SPECIALIZE_CMP(cmp_float, float, float)
PPL_SPECIALIZE_ADD_MUL(add_mul_float, float, float, float)
PPL_SPECIALIZE_SUB_MUL(sub_mul_float, float, float, float)
PPL_SPECIALIZE_INPUT(input_generic, float)
PPL_SPECIALIZE_OUTPUT(output_float, float)
#endif

#if PPL_SUPPORTED_DOUBLE
PPL_SPECIALIZE_CLASSIFY(classify_float, double)
PPL_SPECIALIZE_IS_NAN(is_nan_float, double)
PPL_SPECIALIZE_IS_MINF(is_minf_float, double)
PPL_SPECIALIZE_IS_PINF(is_pinf_float, double)
PPL_SPECIALIZE_ASSIGN_SPECIAL(assign_special_float, double)
PPL_SPECIALIZE_ASSIGN(assign_float_int, double, signed char)
PPL_SPECIALIZE_ASSIGN(assign_float_int, double, signed short)
PPL_SPECIALIZE_ASSIGN(assign_float_int, double, signed int)
PPL_SPECIALIZE_ASSIGN(assign_float_int, double, signed long)
PPL_SPECIALIZE_ASSIGN(assign_float_int, double, signed long long)
PPL_SPECIALIZE_ASSIGN(assign_float_int, double, unsigned char)
PPL_SPECIALIZE_ASSIGN(assign_float_int, double, unsigned short)
PPL_SPECIALIZE_ASSIGN(assign_float_int, double, unsigned int)
PPL_SPECIALIZE_ASSIGN(assign_float_int, double, unsigned long)
PPL_SPECIALIZE_ASSIGN(assign_float_int, double, unsigned long long)
PPL_SPECIALIZE_ASSIGN(assign_float_mpz, double, mpz_class)
PPL_SPECIALIZE_ASSIGN(assign_float_mpq, double, mpq_class)
PPL_SPECIALIZE_COPY(copy_generic, double)
PPL_SPECIALIZE_IS_INT(is_int_float, double)
PPL_SPECIALIZE_FLOOR(floor_float, double, double)
PPL_SPECIALIZE_CEIL(ceil_float, double, double)
PPL_SPECIALIZE_TRUNC(trunc_float, double, double)
PPL_SPECIALIZE_NEG(neg_float, double, double)
PPL_SPECIALIZE_ABS(abs_float, double, double)
PPL_SPECIALIZE_ADD(add_float, double, double, double)
PPL_SPECIALIZE_SUB(sub_float, double, double, double)
PPL_SPECIALIZE_MUL(mul_float, double, double, double)
PPL_SPECIALIZE_DIV(div_float, double, double, double)
PPL_SPECIALIZE_REM(rem_float, double, double, double)
PPL_SPECIALIZE_MUL2EXP(mul2exp_float, double, double)
PPL_SPECIALIZE_DIV2EXP(div2exp_float, double, double)
PPL_SPECIALIZE_SQRT(sqrt_float, double, double)
PPL_SPECIALIZE_GCD(gcd_exact, double, double, double)
PPL_SPECIALIZE_GCDEXT(gcdext_exact, double, double, double, double, double)
PPL_SPECIALIZE_LCM(lcm_gcd_exact, double, double, double)
PPL_SPECIALIZE_SGN(sgn_float, double)
PPL_SPECIALIZE_CMP(cmp_float, double, double)
PPL_SPECIALIZE_ADD_MUL(add_mul_float, double, double, double)
PPL_SPECIALIZE_SUB_MUL(sub_mul_float, double, double, double)
PPL_SPECIALIZE_INPUT(input_generic, double)
PPL_SPECIALIZE_OUTPUT(output_float, double)
#endif

#if PPL_SUPPORTED_LONG_DOUBLE
PPL_SPECIALIZE_CLASSIFY(classify_float, long double)
PPL_SPECIALIZE_IS_NAN(is_nan_float, long double)
PPL_SPECIALIZE_IS_MINF(is_minf_float, long double)
PPL_SPECIALIZE_IS_PINF(is_pinf_float, long double)
PPL_SPECIALIZE_ASSIGN_SPECIAL(assign_special_float, long double)
PPL_SPECIALIZE_ASSIGN(assign_float_int, long double, signed char)
PPL_SPECIALIZE_ASSIGN(assign_float_int, long double, signed short)
PPL_SPECIALIZE_ASSIGN(assign_float_int, long double, signed int)
PPL_SPECIALIZE_ASSIGN(assign_float_int, long double, signed long)
PPL_SPECIALIZE_ASSIGN(assign_float_int, long double, signed long long)
PPL_SPECIALIZE_ASSIGN(assign_float_int, long double, unsigned char)
PPL_SPECIALIZE_ASSIGN(assign_float_int, long double, unsigned short)
PPL_SPECIALIZE_ASSIGN(assign_float_int, long double, unsigned int)
PPL_SPECIALIZE_ASSIGN(assign_float_int, long double, unsigned long)
PPL_SPECIALIZE_ASSIGN(assign_float_int, long double, unsigned long long)
PPL_SPECIALIZE_ASSIGN(assign_float_mpz, long double, mpz_class)
PPL_SPECIALIZE_ASSIGN(assign_float_mpq, long double, mpq_class)
PPL_SPECIALIZE_COPY(copy_generic, long double)
PPL_SPECIALIZE_IS_INT(is_int_float, long double)
PPL_SPECIALIZE_FLOOR(floor_float, long double, long double)
PPL_SPECIALIZE_CEIL(ceil_float, long double, long double)
PPL_SPECIALIZE_TRUNC(trunc_float, long double, long double)
PPL_SPECIALIZE_NEG(neg_float, long double, long double)
PPL_SPECIALIZE_ABS(abs_float, long double, long double)
PPL_SPECIALIZE_ADD(add_float, long double, long double, long double)
PPL_SPECIALIZE_SUB(sub_float, long double, long double, long double)
PPL_SPECIALIZE_MUL(mul_float, long double, long double, long double)
PPL_SPECIALIZE_DIV(div_float, long double, long double, long double)
PPL_SPECIALIZE_REM(rem_float, long double, long double, long double)
PPL_SPECIALIZE_MUL2EXP(mul2exp_float, long double, long double)
PPL_SPECIALIZE_DIV2EXP(div2exp_float, long double, long double)
PPL_SPECIALIZE_SQRT(sqrt_float, long double, long double)
PPL_SPECIALIZE_GCD(gcd_exact, long double, long double, long double)
PPL_SPECIALIZE_GCDEXT(gcdext_exact, long double, long double, long double,
		  long double, long double)
PPL_SPECIALIZE_LCM(lcm_gcd_exact, long double, long double, long double)
PPL_SPECIALIZE_SGN(sgn_float, long double)
PPL_SPECIALIZE_CMP(cmp_float, long double, long double)
PPL_SPECIALIZE_ADD_MUL(add_mul_float, long double, long double, long double)
PPL_SPECIALIZE_SUB_MUL(sub_mul_float, long double, long double, long double)
PPL_SPECIALIZE_INPUT(input_generic, long double)
PPL_SPECIALIZE_OUTPUT(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.
*/


#include <sstream>

namespace Parma_Polyhedra_Library {

namespace Checked {

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

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

#ifdef PPL_HAVE_TYPEOF
//! 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::has_nan || Policy::has_infinity) {
    mp_size_field_t s = get_mp_size(v);
    if (Policy::has_nan
	&& (nan || sign)
	&& s == C_Integer<mp_size_field_t>::min + 1)
      return VC_NAN;
    if (!inf && !sign)
      return VC_NORMAL;
    if (Policy::has_infinity) {
      if (s == C_Integer<mp_size_field_t>::min)
	return inf ? VC_MINUS_INFINITY : V_LT;
      if (s == C_Integer<mp_size_field_t>::max)
	return inf ? VC_PLUS_INFINITY : V_GT;
    }
  }
  if (sign)
    return sgn<Policy>(v);
  return VC_NORMAL;
}

PPL_SPECIALIZE_CLASSIFY(classify_mpz, mpz_class)

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

PPL_SPECIALIZE_IS_NAN(is_nan_mpz, mpz_class)

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

PPL_SPECIALIZE_IS_MINF(is_minf_mpz, mpz_class)

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

PPL_SPECIALIZE_IS_PINF(is_pinf_mpz, mpz_class)

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

PPL_SPECIALIZE_IS_INT(is_int_mpz, mpz_class)

template <typename Policy>
inline Result
assign_special_mpz(mpz_class& v, Result r, Rounding_Dir) {
  Result c = classify(r);
  if (Policy::has_nan && c == VC_NAN)
    set_mp_size(v, C_Integer<mp_size_field_t>::min + 1);
  else if (Policy::has_infinity) {
    switch (c) {
    case VC_MINUS_INFINITY:
      set_mp_size(v, C_Integer<mp_size_field_t>::min);
      return V_EQ;
    case VC_PLUS_INFINITY:
      set_mp_size(v, C_Integer<mp_size_field_t>::max);
      return V_EQ;
    default:
      break;
    }
  }
  return r;
}

PPL_SPECIALIZE_ASSIGN_SPECIAL(assign_special_mpz, mpz_class)

template <typename To_Policy, typename From_Policy>
inline void
copy_mpz(mpz_class& to, const mpz_class& from) {
  if (is_nan_mpz<From_Policy>(from))
    assert(To_Policy::has_nan);
  else if (is_minf_mpz<From_Policy>(from) || is_pinf_mpz<From_Policy>(from))
    assert(To_Policy::has_infinity);
  else {
    to = from;
    return;
  }
  set_mp_size(to, get_mp_size(from));
}

PPL_SPECIALIZE_COPY(copy_mpz, mpz_class)

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

PPL_SPECIALIZE_CONSTRUCT(construct_mpz_base, mpz_class, signed char)
PPL_SPECIALIZE_CONSTRUCT(construct_mpz_base, mpz_class, signed short)
PPL_SPECIALIZE_CONSTRUCT(construct_mpz_base, mpz_class, signed int)
PPL_SPECIALIZE_CONSTRUCT(construct_mpz_base, mpz_class, signed long)
PPL_SPECIALIZE_CONSTRUCT(construct_mpz_base, mpz_class, unsigned char)
PPL_SPECIALIZE_CONSTRUCT(construct_mpz_base, mpz_class, unsigned short)
PPL_SPECIALIZE_CONSTRUCT(construct_mpz_base, mpz_class, unsigned int)
PPL_SPECIALIZE_CONSTRUCT(construct_mpz_base, mpz_class, unsigned long)

template <typename To_Policy, typename From_Policy, typename From>
inline Result
construct_mpz_float(mpz_class& to, const From& from, Rounding_Dir dir) {
  if (is_nan<From_Policy>(from))
    return construct_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
  else if (is_minf<From_Policy>(from))
    return construct_special<To_Policy>(to, VC_MINUS_INFINITY, dir);
  else if (is_pinf<From_Policy>(from))
    return construct_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
  if (round_ignore(dir)) {
    new (&to) mpz_class(from);
    return V_LGE;
  }
  From n = rint(from);
  new (&to) mpz_class(n);
  if (from < n)
    return round_lt_mpz<To_Policy>(to, dir);
  else if (from > n)
    return round_gt_mpz<To_Policy>(to, dir);
  else
    return V_EQ;
}

PPL_SPECIALIZE_CONSTRUCT(construct_mpz_float, mpz_class, float)
PPL_SPECIALIZE_CONSTRUCT(construct_mpz_float, mpz_class, double)

PPL_SPECIALIZE_ASSIGN(assign_exact, mpz_class, mpz_class)
PPL_SPECIALIZE_ASSIGN(assign_exact, mpz_class, signed char)
PPL_SPECIALIZE_ASSIGN(assign_exact, mpz_class, signed short)
PPL_SPECIALIZE_ASSIGN(assign_exact, mpz_class, signed int)
PPL_SPECIALIZE_ASSIGN(assign_exact, mpz_class, signed long)
PPL_SPECIALIZE_ASSIGN(assign_exact, mpz_class, unsigned char)
PPL_SPECIALIZE_ASSIGN(assign_exact, mpz_class, unsigned short)
PPL_SPECIALIZE_ASSIGN(assign_exact, mpz_class, unsigned int)
PPL_SPECIALIZE_ASSIGN(assign_exact, mpz_class, unsigned long)

template <typename To_Policy, typename From_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;
}

PPL_SPECIALIZE_ASSIGN(assign_mpz_signed_int, mpz_class, signed long long)

template <typename To_Policy, typename From_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;
}

PPL_SPECIALIZE_ASSIGN(assign_mpz_unsigned_int, mpz_class, unsigned long long)

template <typename To_Policy, typename From_Policy, typename From>
inline Result
assign_mpz_float(mpz_class& to, const From from, Rounding_Dir dir) {
  if (is_nan<From_Policy>(from))
    return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
  else if (is_minf<From_Policy>(from))
    return assign_special<To_Policy>(to, VC_MINUS_INFINITY, dir);
  else if (is_pinf<From_Policy>(from))
    return assign_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
  if (round_ignore(dir)) {
    to = from;
    return V_LGE;
  }
  From n = rint(from);
  to = n;
  if (from < n)
    return round_lt_mpz<To_Policy>(to, dir);
  else if (from > n)
    return round_gt_mpz<To_Policy>(to, dir);
  else
    return V_EQ;
}

PPL_SPECIALIZE_ASSIGN(assign_mpz_float, mpz_class, float)
PPL_SPECIALIZE_ASSIGN(assign_mpz_float, mpz_class, double)

template <typename To_Policy, typename From_Policy, typename From>
inline Result
assign_mpz_long_double(mpz_class& to, const From& from, Rounding_Dir dir) {
  if (is_nan<From_Policy>(from))
    return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
  else if (is_minf<From_Policy>(from))
    return assign_special<To_Policy>(to, VC_MINUS_INFINITY, dir);
  else if (is_pinf<From_Policy>(from))
    return assign_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
  // FIXME: this is an incredibly inefficient implementation!
  std::stringstream ss;
  output<From_Policy>(ss, from, Numeric_Format(), dir);
  PPL_DIRTY_TEMP0(mpq_class, tmp);
#ifndef NDEBUG
  Result r =
#endif
    input_mpq(tmp, ss);
  assert(r == V_EQ);
  return assign<To_Policy, From_Policy>(to, tmp, dir);
}

PPL_SPECIALIZE_ASSIGN(assign_mpz_long_double, mpz_class, long double)

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

PPL_SPECIALIZE_ASSIGN(assign_mpz_mpq, mpz_class, mpq_class)

PPL_SPECIALIZE_FLOOR(assign_exact, mpz_class, mpz_class)
PPL_SPECIALIZE_CEIL(assign_exact, mpz_class, mpz_class)
PPL_SPECIALIZE_TRUNC(assign_exact, mpz_class, mpz_class)

template <typename To_Policy, typename From_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;
}

PPL_SPECIALIZE_NEG(neg_mpz, mpz_class, mpz_class)

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

PPL_SPECIALIZE_ADD(add_mpz, mpz_class, mpz_class, mpz_class)

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

PPL_SPECIALIZE_SUB(sub_mpz, mpz_class, mpz_class, mpz_class)

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

PPL_SPECIALIZE_MUL(mul_mpz, mpz_class, mpz_class, mpz_class)

template <typename To_Policy, typename From1_Policy, typename From2_Policy>
inline Result
div_mpz(mpz_class& to, const mpz_class& x, const mpz_class& y,
	Rounding_Dir dir) {
  if (CHECK_P(To_Policy::check_div_zero, ::sgn(y) == 0))
    return assign_special<To_Policy>(to, V_DIV_ZERO, ROUND_IGNORE);
  mpz_srcptr n = x.get_mpz_t();
  mpz_srcptr d = y.get_mpz_t();
  if (round_ignore(dir)) {
#if 0
    // FIXME: we need to reconsider Rounding_Dir argument to clarify if
    // client code intention is to have approximate result without any interest
    // in knowing the direction of rounding or to grant to called function
    // that result will be exact.
    mpz_divexact(to.get_mpz_t(), n, d);
    return V_LGE;
#else
    mpz_cdiv_q(to.get_mpz_t(), n, d);
    return V_LE;
#endif
  }
  if (round_down(dir)) {
    mpz_fdiv_q(to.get_mpz_t(), n, d);
    return mpz_divisible_p(n, d) ? V_EQ : V_GT;
  }
  else {
    assert(round_up(dir));
    mpz_cdiv_q(to.get_mpz_t(), n, d);
    return mpz_divisible_p(n, d) ? V_EQ : V_LT;
  }
}

PPL_SPECIALIZE_DIV(div_mpz, mpz_class, mpz_class, mpz_class)

template <typename To_Policy, typename From1_Policy, typename From2_Policy>
inline Result
idiv_mpz(mpz_class& to, const mpz_class& x, const mpz_class& y,
	Rounding_Dir) {
  if (CHECK_P(To_Policy::check_div_zero, ::sgn(y) == 0))
    return assign_special<To_Policy>(to, V_DIV_ZERO, ROUND_IGNORE);
  mpz_srcptr n = x.get_mpz_t();
  mpz_srcptr d = y.get_mpz_t();
  mpz_tdiv_q(to.get_mpz_t(), n, d);
  return V_EQ;
}

PPL_SPECIALIZE_IDIV(idiv_mpz, mpz_class, mpz_class, mpz_class)

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

PPL_SPECIALIZE_REM(rem_mpz, mpz_class, mpz_class, mpz_class)

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

PPL_SPECIALIZE_MUL2EXP(mul2exp_mpz, mpz_class, mpz_class)

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

PPL_SPECIALIZE_DIV2EXP(div2exp_mpz, mpz_class, mpz_class)

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

PPL_SPECIALIZE_ABS(abs_mpz, mpz_class, mpz_class)

template <typename To_Policy, typename From1_Policy, typename From2_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;
}

PPL_SPECIALIZE_ADD_MUL(add_mul_mpz, mpz_class, mpz_class, mpz_class)

template <typename To_Policy, typename From1_Policy, typename From2_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;
}

PPL_SPECIALIZE_SUB_MUL(sub_mul_mpz, mpz_class, mpz_class, mpz_class)

template <typename To_Policy, typename From1_Policy, typename From2_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;
}

PPL_SPECIALIZE_GCD(gcd_mpz, mpz_class, mpz_class, mpz_class)

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

PPL_SPECIALIZE_GCDEXT(gcdext_mpz, mpz_class, mpz_class, mpz_class, mpz_class, mpz_class)

template <typename To_Policy, typename From1_Policy, typename From2_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;
}

PPL_SPECIALIZE_LCM(lcm_mpz, mpz_class, mpz_class, mpz_class)

template <typename To_Policy, typename From_Policy>
inline Result
sqrt_mpz(mpz_class& to, const mpz_class& from, Rounding_Dir dir) {
  if (CHECK_P(To_Policy::check_sqrt_neg, from < 0))
    return assign_special<To_Policy>(to, V_SQRT_NEG, ROUND_IGNORE);
  if (round_ignore(dir)) {
    to = sqrt(from);
    return V_GE;
  }
  PPL_DIRTY_TEMP0(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<To_Policy>(to, dir);
}

PPL_SPECIALIZE_SQRT(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;
}

PPL_SPECIALIZE_SGN(sgn_mp, mpz_class)
PPL_SPECIALIZE_SGN(sgn_mp, mpq_class)

template <typename Policy1, typename Policy2, 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;
}

PPL_SPECIALIZE_CMP(cmp_mp, mpz_class, mpz_class)
PPL_SPECIALIZE_CMP(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;
}

PPL_SPECIALIZE_INPUT(input_generic, mpz_class)
PPL_SPECIALIZE_OUTPUT(output_mpz, mpz_class)

} // 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::has_nan || Policy::has_infinity)
      && ::sgn(v.get_den()) == 0) {
    int s = ::sgn(v.get_num());
    if (Policy::has_nan && (nan || sign) && s == 0)
      return VC_NAN;
    if (!inf && !sign)
      return VC_NORMAL;
    if (Policy::has_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;
}

PPL_SPECIALIZE_CLASSIFY(classify_mpq, mpq_class)

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

PPL_SPECIALIZE_IS_NAN(is_nan_mpq, mpq_class)

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

PPL_SPECIALIZE_IS_MINF(is_minf_mpq, mpq_class)

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

PPL_SPECIALIZE_IS_PINF(is_pinf_mpq, mpq_class)

template <typename Policy>
inline bool
is_int_mpq(const mpq_class& v) {
  if ((Policy::has_infinity || Policy::has_nan)
      && ::sgn(v.get_den()) == 0)
    return !(Policy::has_nan && ::sgn(v.get_num()) == 0);
  else
    return v.get_den() == 1;
}

PPL_SPECIALIZE_IS_INT(is_int_mpq, mpq_class)

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

PPL_SPECIALIZE_ASSIGN_SPECIAL(assign_special_mpq, mpq_class)

PPL_SPECIALIZE_COPY(copy_generic, mpq_class)

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

PPL_SPECIALIZE_CONSTRUCT(construct_mpq_base, mpq_class, mpz_class)
PPL_SPECIALIZE_CONSTRUCT(construct_mpq_base, mpq_class, signed char)
PPL_SPECIALIZE_CONSTRUCT(construct_mpq_base, mpq_class, signed short)
PPL_SPECIALIZE_CONSTRUCT(construct_mpq_base, mpq_class, signed int)
PPL_SPECIALIZE_CONSTRUCT(construct_mpq_base, mpq_class, signed long)
PPL_SPECIALIZE_CONSTRUCT(construct_mpq_base, mpq_class, unsigned char)
PPL_SPECIALIZE_CONSTRUCT(construct_mpq_base, mpq_class, unsigned short)
PPL_SPECIALIZE_CONSTRUCT(construct_mpq_base, mpq_class, unsigned int)
PPL_SPECIALIZE_CONSTRUCT(construct_mpq_base, mpq_class, unsigned long)

template <typename To_Policy, typename From_Policy, typename From>
inline Result
construct_mpq_float(mpq_class& to, const From& from, Rounding_Dir dir) {
  if (is_nan<From_Policy>(from))
    return construct_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
  else if (is_minf<From_Policy>(from))
    return construct_special<To_Policy>(to, VC_MINUS_INFINITY, dir);
  else if (is_pinf<From_Policy>(from))
    return construct_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
  new (&to) mpq_class(from);
  return V_EQ;
}

PPL_SPECIALIZE_CONSTRUCT(construct_mpq_float, mpq_class, float)
PPL_SPECIALIZE_CONSTRUCT(construct_mpq_float, mpq_class, double)

PPL_SPECIALIZE_ASSIGN(assign_exact, mpq_class, mpq_class)
PPL_SPECIALIZE_ASSIGN(assign_exact, mpq_class, mpz_class)
PPL_SPECIALIZE_ASSIGN(assign_exact, mpq_class, signed char)
PPL_SPECIALIZE_ASSIGN(assign_exact, mpq_class, signed short)
PPL_SPECIALIZE_ASSIGN(assign_exact, mpq_class, signed int)
PPL_SPECIALIZE_ASSIGN(assign_exact, mpq_class, signed long)
PPL_SPECIALIZE_ASSIGN(assign_exact, mpq_class, unsigned char)
PPL_SPECIALIZE_ASSIGN(assign_exact, mpq_class, unsigned short)
PPL_SPECIALIZE_ASSIGN(assign_exact, mpq_class, unsigned int)
PPL_SPECIALIZE_ASSIGN(assign_exact, mpq_class, unsigned long)

template <typename To_Policy, typename From_Policy, typename From>
inline Result
assign_mpq_float(mpq_class& to, const From& from, Rounding_Dir dir) {
  if (is_nan<From_Policy>(from))
    return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
  else if (is_minf<From_Policy>(from))
    return assign_special<To_Policy>(to, VC_MINUS_INFINITY, dir);
  else if (is_pinf<From_Policy>(from))
    return assign_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
  to = from;
  return V_EQ;
}

PPL_SPECIALIZE_ASSIGN(assign_mpq_float, mpq_class, float)
PPL_SPECIALIZE_ASSIGN(assign_mpq_float, mpq_class, double)

template <typename To_Policy, typename From_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;
}

PPL_SPECIALIZE_ASSIGN(assign_mpq_signed_int, mpq_class, signed long long)

template <typename To_Policy, typename From_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;
}

PPL_SPECIALIZE_ASSIGN(assign_mpq_unsigned_int, mpq_class, unsigned long long)

template <typename To_Policy, typename From_Policy>
inline Result
floor_mpq(mpq_class& to, const mpq_class& from, Rounding_Dir) {
  mpz_fdiv_q(to.get_num().get_mpz_t(),
	     from.get_num().get_mpz_t(), from.get_den().get_mpz_t());
  to.get_den() = 1;
  return V_EQ;
}

PPL_SPECIALIZE_FLOOR(floor_mpq, mpq_class, mpq_class)

template <typename To_Policy, typename From_Policy>
inline Result
ceil_mpq(mpq_class& to, const mpq_class& from, Rounding_Dir) {
  mpz_cdiv_q(to.get_num().get_mpz_t(),
	     from.get_num().get_mpz_t(), from.get_den().get_mpz_t());
  to.get_den() = 1;
  return V_EQ;
}

PPL_SPECIALIZE_CEIL(ceil_mpq, mpq_class, mpq_class)

template <typename To_Policy, typename From_Policy>
inline Result
trunc_mpq(mpq_class& to, const mpq_class& from, Rounding_Dir) {
  mpz_tdiv_q(to.get_num().get_mpz_t(),
	     from.get_num().get_mpz_t(), from.get_den().get_mpz_t());
  to.get_den() = 1;
  return V_EQ;
}

PPL_SPECIALIZE_TRUNC(trunc_mpq, mpq_class, mpq_class)

template <typename To_Policy, typename From_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;
}

PPL_SPECIALIZE_NEG(neg_mpq, mpq_class, mpq_class)

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

PPL_SPECIALIZE_ADD(add_mpq, mpq_class, mpq_class, mpq_class)

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

PPL_SPECIALIZE_SUB(sub_mpq, mpq_class, mpq_class, mpq_class)

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

PPL_SPECIALIZE_MUL(mul_mpq, mpq_class, mpq_class, mpq_class)

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

PPL_SPECIALIZE_DIV(div_mpq, mpq_class, mpq_class, mpq_class)

template <typename To_Policy, typename From1_Policy, typename From2_Policy>
inline Result
idiv_mpq(mpq_class& to, const mpq_class& x, const mpq_class& y, Rounding_Dir dir) {
  if (CHECK_P(To_Policy::check_div_zero, sgn(y) == 0))
    return assign_special<To_Policy>(to, V_DIV_ZERO, ROUND_IGNORE);
  to = x / y;
  return trunc<To_Policy, To_Policy>(to, to, dir);
}

PPL_SPECIALIZE_IDIV(idiv_mpq, mpq_class, mpq_class, mpq_class)

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

PPL_SPECIALIZE_REM(rem_mpq, mpq_class, mpq_class, mpq_class)

template <typename To_Policy, typename From_Policy>
inline Result
mul2exp_mpq(mpq_class& to, const mpq_class& x, int exp, Rounding_Dir dir) {
  if (exp < 0)
    return div2exp<To_Policy, From_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;
}

PPL_SPECIALIZE_MUL2EXP(mul2exp_mpq, mpq_class, mpq_class)

template <typename To_Policy, typename From_Policy>
inline Result
div2exp_mpq(mpq_class& to, const mpq_class& x, int exp, Rounding_Dir dir) {
  if (exp < 0)
    return mul2exp<To_Policy, From_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;
}

PPL_SPECIALIZE_DIV2EXP(div2exp_mpq, mpq_class, mpq_class)

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

PPL_SPECIALIZE_ABS(abs_mpq, mpq_class, mpq_class)

template <typename To_Policy, typename From1_Policy, typename From2_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;
}

PPL_SPECIALIZE_ADD_MUL(add_mul_mpq, mpq_class, mpq_class, mpq_class)

template <typename To_Policy, typename From1_Policy, typename From2_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;
}

PPL_SPECIALIZE_SUB_MUL(sub_mul_mpq, mpq_class, mpq_class, mpq_class)

extern unsigned long rational_sqrt_precision_parameter;

template <typename To_Policy, typename From_Policy>
inline Result
sqrt_mpq(mpq_class& to, const mpq_class& from, Rounding_Dir dir) {
  if (CHECK_P(To_Policy::check_sqrt_neg, from < 0))
    return assign_special<To_Policy>(to, V_SQRT_NEG, ROUND_IGNORE);
  if (from == 0) {
    to = 0;
    return V_EQ;
  }
  bool gt1 = from.get_num() > from.get_den();
  const mpz_class& from_a = gt1 ? from.get_num() : from.get_den();
  const mpz_class& from_b = gt1 ? from.get_den() : from.get_num();
  mpz_class& to_a = gt1 ? to.get_num() : to.get_den();
  mpz_class& to_b = gt1 ? to.get_den() : to.get_num();
  Rounding_Dir rdir = gt1 ? dir : inverse(dir);
  mul2exp<To_Policy, From_Policy>(to_a, from_a, 2*rational_sqrt_precision_parameter, ROUND_IGNORE);
  Result rdiv
    = div<To_Policy, To_Policy, To_Policy>(to_a, to_a, from_b, rdir);
  Result rsqrt = sqrt<To_Policy, To_Policy>(to_a, to_a, rdir);
  to_b = 1;
  mul2exp<To_Policy, To_Policy>(to_b, to_b, rational_sqrt_precision_parameter, ROUND_IGNORE);
  to.canonicalize();
  return rdiv != V_EQ ? rdiv : rsqrt;
}

PPL_SPECIALIZE_SQRT(sqrt_mpq, mpq_class, mpq_class)

template <typename Policy>
inline Result
input_mpq(mpq_class& to, std::istream& is, Rounding_Dir) {
  Result r = input_mpq(to, is);
  switch (classify(r)) {
  case VC_MINUS_INFINITY:
  case VC_PLUS_INFINITY:
  case VC_NAN:
    return assign_special<Policy>(to, r, ROUND_IGNORE);
  default:
    return r;
  }
}

PPL_SPECIALIZE_INPUT(input_mpq, mpq_class)

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

PPL_SPECIALIZE_OUTPUT(output_mpq, mpq_class)

template <typename To_Policy, typename From_Policy, typename From>
inline Result
assign_mpq_long_double(mpq_class& to, const From& from, Rounding_Dir dir) {
  if (is_nan<From_Policy>(from))
    return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
  else if (is_minf<From_Policy>(from))
    return assign_special<To_Policy>(to, VC_MINUS_INFINITY, dir);
  else if (is_pinf<From_Policy>(from))
    return assign_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
  // FIXME: this is an incredibly inefficient implementation!
  std::stringstream ss;
  output<From_Policy>(ss, from, Numeric_Format(), dir);
  return input_mpq(to, ss);
}

PPL_SPECIALIZE_ASSIGN(assign_mpq_long_double, mpq_class, long double)

} // 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.
/*! The lesser between numerator and denominator is limited to 2**\p p.

  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 {

template <typename T> struct FPU_Related : public False {};
template <> struct FPU_Related<float> : public True {};
template <> struct FPU_Related<double> : public True {};
template <> struct FPU_Related<long double> : public True {};

namespace Checked {

template <typename T>
inline bool
handle_ext_natively(const T&) {
  return FPU_Related<T>::value;
}

template <typename Policy, typename Type>
inline bool
ext_to_handle(const Type& x) {
  return !handle_ext_natively(x)
    && (Policy::has_infinity || Policy::has_nan);
}

template <typename Policy, typename Type>
inline Result
sgn_ext(const Type& x) {
  if (!ext_to_handle<Policy>(x))
    goto native;
  if (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 {
  native:
    return sgn<Policy>(x);
  }
}

template <typename To_Policy, typename From_Policy,
	  typename To, typename From>
inline Result
construct_ext(To& to, const From& x, Rounding_Dir dir) {
  if (!ext_to_handle<From_Policy>(x))
    goto native;
  if (is_nan<From_Policy>(x))
    return construct_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
  else if (is_minf<From_Policy>(x))
    return construct_special<To_Policy>(to, VC_MINUS_INFINITY, dir);
  else if (is_pinf<From_Policy>(x))
    return construct_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
  else {
  native:
    return construct<To_Policy, From_Policy>(to, x, dir);
  }
}

template <typename To_Policy, typename From_Policy,
	  typename To, typename From>
inline Result
assign_ext(To& to, const From& x, Rounding_Dir dir) {
  if (!ext_to_handle<From_Policy>(x))
    goto native;
  if (is_nan<From_Policy>(x))
    return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
  else if (is_minf<From_Policy>(x))
    return assign_special<To_Policy>(to, VC_MINUS_INFINITY, dir);
  else if (is_pinf<From_Policy>(x))
    return assign_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
  else {
  native:
    return assign<To_Policy, From_Policy>(to, x, 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 (!ext_to_handle<From_Policy>(x))
    goto native;
  if (is_nan<From_Policy>(x))
    return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
  else if (is_minf<From_Policy>(x))
    return assign_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
  else if (is_pinf<From_Policy>(x))
    return assign_special<To_Policy>(to, VC_MINUS_INFINITY, dir);
  else {
  native:
    return neg<To_Policy, From_Policy>(to, x, dir);
  }
}

template <typename To_Policy, typename From_Policy,
	  typename To, typename From>
inline Result
floor_ext(To& to, const From& x, Rounding_Dir dir) {
  if (!ext_to_handle<From_Policy>(x))
    goto native;
  if (is_nan<From_Policy>(x))
    return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
  else if (is_minf<From_Policy>(x))
    return assign_special<To_Policy>(to, VC_MINUS_INFINITY, dir);
  else if (is_pinf<From_Policy>(x))
    return assign_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
  else {
  native:
    return floor<To_Policy, From_Policy>(to, x, dir);
  }
}

template <typename To_Policy, typename From_Policy,
	  typename To, typename From>
inline Result
ceil_ext(To& to, const From& x, Rounding_Dir dir) {
  if (!ext_to_handle<From_Policy>(x))
    goto native;
  if (is_nan<From_Policy>(x))
    return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
  else if (is_minf<From_Policy>(x))
    return assign_special<To_Policy>(to, VC_MINUS_INFINITY, dir);
  else if (is_pinf<From_Policy>(x))
    return assign_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
  else {
  native:
    return ceil<To_Policy, From_Policy>(to, x, dir);
  }
}

template <typename To_Policy, typename From_Policy,
	  typename To, typename From>
inline Result
trunc_ext(To& to, const From& x, Rounding_Dir dir) {
  if (!ext_to_handle<From_Policy>(x))
    goto native;
  if (is_nan<From_Policy>(x))
    return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
  else if (is_minf<From_Policy>(x))
    return assign_special<To_Policy>(to, VC_MINUS_INFINITY, dir);
  else if (is_pinf<From_Policy>(x))
    return assign_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
  else {
  native:
    return trunc<To_Policy, From_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 (!ext_to_handle<From_Policy>(x))
    goto native;
  if (is_nan<From_Policy>(x))
    return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
  else if (is_minf<From_Policy>(x) || is_pinf<From_Policy>(x))
    return assign_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
  else {
  native:
    return abs<To_Policy, From_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 (!ext_to_handle<From1_Policy>(x) && !ext_to_handle<From2_Policy>(y))
    goto native;
  if (is_nan<From1_Policy>(x) || is_nan<From2_Policy>(y))
    return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
  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 assign_special<To_Policy>(to, V_INF_ADD_INF, ROUND_IGNORE);
    }
    else
      goto pinf;
  }
  else {
    if (is_minf<From2_Policy>(y)) {
    minf:
      return assign_special<To_Policy>(to, VC_MINUS_INFINITY, dir);
    }
    else if (is_pinf<From2_Policy>(y)) {
    pinf:
      return assign_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
    }
    else {
    native:
      return add<To_Policy, From1_Policy, From2_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 (!ext_to_handle<From1_Policy>(x) && !ext_to_handle<From2_Policy>(y))
    goto native;
  if (is_nan<From1_Policy>(x) || is_nan<From2_Policy>(y))
    return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
  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 assign_special<To_Policy>(to, V_INF_SUB_INF, ROUND_IGNORE);
    }
    else
      goto pinf;
  }
  else {
    if (is_pinf<From2_Policy>(y)) {
    minf:
      return assign_special<To_Policy>(to, VC_MINUS_INFINITY, dir);
    }
    else if (is_minf<From2_Policy>(y)) {
    pinf:
      return assign_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
    }
    else {
    native:
      return sub<To_Policy, From1_Policy, From2_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 (!ext_to_handle<From1_Policy>(x) && !ext_to_handle<From2_Policy>(y))
    goto native;
  if (is_nan<From1_Policy>(x) || is_nan<From2_Policy>(y))
    return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
  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_special<To_Policy>(to, VC_MINUS_INFINITY, dir);
      case V_GT:
      pinf:
	return assign_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
      default:
      inf_mul_zero:
	assert(To_Policy::check_inf_mul_zero);
	return assign_special<To_Policy>(to, V_INF_MUL_ZERO, ROUND_IGNORE);
      }
    }
    else {
    native:
      return mul<To_Policy, From1_Policy, From2_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 (!ext_to_handle<To_Policy>(to)
      && !ext_to_handle<From1_Policy>(x) && !ext_to_handle<From2_Policy>(y))
    goto native;
  if (is_nan<To_Policy>(to)
      || is_nan<From1_Policy>(x) || is_nan<From2_Policy>(y))
    return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
  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 assign_special<To_Policy>(to, V_INF_ADD_INF, ROUND_IGNORE);
	}
	else
	  goto pinf;
      default:
      inf_mul_zero:
	assert(To_Policy::check_inf_mul_zero);
	return assign_special<To_Policy>(to, V_INF_MUL_ZERO, ROUND_IGNORE);
      }
    }
    else {
      if (is_minf<To_Policy>(to)) {
      minf:
	return assign_special<To_Policy>(to, VC_MINUS_INFINITY, dir);
      }
      if (is_pinf<To_Policy>(to)) {
      pinf:
	return assign_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
      }
    native:
      return add_mul<To_Policy, From1_Policy, From2_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 (!ext_to_handle<To_Policy>(to)
      && !ext_to_handle<From1_Policy>(x) && !ext_to_handle<From2_Policy>(y))
    goto native;
  if (is_nan<To_Policy>(to)
      || is_nan<From1_Policy>(x) || is_nan<From2_Policy>(y))
    return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
  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 assign_special<To_Policy>(to, V_INF_SUB_INF, ROUND_IGNORE);
	}
	else
	  goto minf;
      default:
      inf_mul_zero:
	assert(To_Policy::check_inf_mul_zero);
	return assign_special<To_Policy>(to, V_INF_MUL_ZERO, ROUND_IGNORE);
      }
    }
    else {
      if (is_minf<To_Policy>(to)) {
      minf:
	return assign_special<To_Policy>(to, VC_MINUS_INFINITY, dir);
      }
      if (is_pinf<To_Policy>(to)) {
      pinf:
	return assign_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
      }
    native:
      return sub_mul<To_Policy, From1_Policy, From2_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 (!ext_to_handle<From1_Policy>(x) && !ext_to_handle<From2_Policy>(y))
    goto native;
  if (is_nan<From1_Policy>(x) || is_nan<From2_Policy>(y))
    return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
  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 assign_special<To_Policy>(to, V_INF_DIV_INF, ROUND_IGNORE);
    }
    else {
      switch (sgn<From2_Policy>(y)) {
      case V_LT:
      minf:
	return assign_special<To_Policy>(to, VC_MINUS_INFINITY, dir);
      case V_GT:
      pinf:
	return assign_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
      default:
      div_zero:
	assert(To_Policy::check_div_zero);
	return assign_special<To_Policy>(to, V_DIV_ZERO, ROUND_IGNORE);
      }
    }
  }
  else {
    if (is_minf<From2_Policy>(y) || is_pinf<From2_Policy>(y)) {
      to = 0;
      return V_EQ;
    }
    else {
    native:
      return div<To_Policy, From1_Policy, From2_Policy>(to, x, y, dir);
    }
  }
}


template <typename To_Policy, typename From1_Policy, typename From2_Policy,
	  typename To, typename From1, typename From2>
inline Result
idiv_ext(To& to, const From1& x, const From2& y, Rounding_Dir dir) {
  if (!ext_to_handle<From1_Policy>(x) && !ext_to_handle<From2_Policy>(y))
    goto native;
  if (is_nan<From1_Policy>(x) || is_nan<From2_Policy>(y))
    return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
  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 assign_special<To_Policy>(to, V_INF_DIV_INF, ROUND_IGNORE);
    }
    else {
      switch (sgn<From2_Policy>(y)) {
      case V_LT:
      minf:
	return assign_special<To_Policy>(to, VC_MINUS_INFINITY, dir);
      case V_GT:
      pinf:
	return assign_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
      default:
      div_zero:
	assert(To_Policy::check_div_zero);
	return assign_special<To_Policy>(to, V_DIV_ZERO, ROUND_IGNORE);
      }
    }
  }
  else {
    if (is_minf<From2_Policy>(y) || is_pinf<From2_Policy>(y)) {
      to = 0;
      return V_EQ;
    }
    else {
    native:
      return idiv<To_Policy, From1_Policy, From2_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 (!ext_to_handle<From1_Policy>(x) && !ext_to_handle<From2_Policy>(y))
    goto native;
  if (is_nan<From1_Policy>(x) || is_nan<From2_Policy>(y))
    return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
  else if (CHECK_P(To_Policy::check_inf_mod, is_minf<From1_Policy>(x)
		   || is_pinf<From1_Policy>(x)))
    return assign_special<To_Policy>(to, V_INF_MOD, ROUND_IGNORE);
  else {
    if (is_minf<From1_Policy>(y) || is_pinf<From2_Policy>(y)) {
      to = x;
      return V_EQ;
    }
    else {
    native:
      return rem<To_Policy, From1_Policy, From2_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 (!ext_to_handle<From_Policy>(x))
    goto native;
  if (is_nan<From_Policy>(x))
    return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
  else if (is_minf<From_Policy>(x))
    return assign_special<To_Policy>(to, VC_MINUS_INFINITY, dir);
  else if (is_pinf<From_Policy>(x))
    return assign_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
  else {
  native:
    return mul2exp<To_Policy, From_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 (!ext_to_handle<From_Policy>(x))
    goto native;
  if (is_nan<From_Policy>(x))
    return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
  else if (is_minf<From_Policy>(x))
    return assign_special<To_Policy>(to, VC_MINUS_INFINITY, dir);
  else if (is_pinf<From_Policy>(x))
    return assign_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
  else {
  native:
    return div2exp<To_Policy, From_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 (!ext_to_handle<From_Policy>(x))
    goto native;
  if (is_nan<From_Policy>(x))
    return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
  else if (is_minf<From_Policy>(x))
    return assign_special<To_Policy>(to, V_SQRT_NEG, ROUND_IGNORE);
  else if (is_pinf<From_Policy>(x))
    return assign_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
  else {
  native:
    return sqrt<To_Policy, From_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 (is_nan<From1_Policy>(x) || is_nan<From2_Policy>(y))
    return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
  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, From1_Policy, From2_Policy>(to, x, y, dir);
}

template <typename To1_Policy, typename To2_Policy, typename To3_Policy,
	  typename From1_Policy, typename From2_Policy,
	  typename To1, typename To2, typename To3,
	  typename From1, typename From2>
inline Result
gcdext_ext(To1& to, To2& s, To3& t, const From1& x, const From2& y,
	   Rounding_Dir dir) {
  if (is_nan<From1_Policy>(x) || is_nan<From2_Policy>(y))
    return assign_special<To1_Policy>(to, VC_NAN, ROUND_IGNORE);
  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, To2_Policy, To3_Policy, From1_Policy, From2_Policy>(to, s, t, x, y, 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 (is_nan<From1_Policy>(x) || is_nan<From2_Policy>(y))
    return assign_special<To_Policy>(to, VC_NAN, ROUND_IGNORE);
  else if (is_minf<From1_Policy>(x) || is_pinf<From1_Policy>(x)
	   || is_minf<From2_Policy>(y) || is_pinf<From2_Policy>(y))
    return assign_special<To_Policy>(to, VC_PLUS_INFINITY, dir);
  else
    return lcm<To_Policy, From1_Policy, From2_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 (!ext_to_handle<Policy1>(x) && !ext_to_handle<Policy2>(y))
    goto native;
  if (is_nan<Policy1>(x) || 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, Policy2>(x, y);
  }
}

template <typename Policy1, typename Policy2,
	  typename Type1, typename Type2>
inline bool
lt_ext(const Type1& x, const Type2& y) {
  if (!ext_to_handle<Policy1>(x) && !ext_to_handle<Policy2>(y))
    goto native;
  if (is_nan<Policy1>(x) || 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 lt_p<Policy1, Policy2>(x, y);
}

template <typename Policy1, typename Policy2,
	  typename Type1, typename Type2>
inline bool
gt_ext(const Type1& x, const Type2& y) {
  return lt_ext<Policy1, Policy2>(y, x);
}

template <typename Policy1, typename Policy2,
	  typename Type1, typename Type2>
inline bool
le_ext(const Type1& x, const Type2& y) {
  if (!ext_to_handle<Policy1>(x) && !ext_to_handle<Policy2>(y))
    goto native;
  if (is_nan<Policy1>(x) || 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 le_p<Policy1, Policy2>(x, y);
}

template <typename Policy1, typename Policy2,
	  typename Type1, typename Type2>
inline bool
ge_ext(const Type1& x, const Type2& y) {
  return le_ext<Policy1, Policy2>(y, x);
}

template <typename Policy1, typename Policy2,
	  typename Type1, typename Type2>
inline bool
eq_ext(const Type1& x, const Type2& y) {
  if (!ext_to_handle<Policy1>(x) && !ext_to_handle<Policy2>(y))
    goto native;
  if (is_nan<Policy1>(x) || 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);
  else if (is_minf<Policy2>(y) || is_pinf<Policy2>(y))
    return false;
 native:
  return eq_p<Policy1, Policy2>(x, y);
}

template <typename Policy1, typename Policy2,
	  typename Type1, typename Type2>
inline bool
ne_ext(const Type1& x, const Type2& y) {
  return !eq_ext<Policy1, Policy2>(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 (!ext_to_handle<Policy>(x))
    goto native;
  if (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 601. */

#undef nonconst
#ifdef PPL_SAVED_nonconst
#define nonconst PPL_SAVED_nonconst
#undef PPL_SAVED_nonconst
#endif

#undef PPL_FUNCTION_CLASS
#undef PPL_NAN

/* Automatically generated from PPL source file ../src/Checked_Number.defs.hh line 30. */
#include <iosfwd>

namespace Parma_Polyhedra_Library {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \ingroup PPL_CXX_interface */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
struct Checked_Number_Default_Policy {
  const_bool_nodef(check_overflow, true);
  const_bool_nodef(check_inf_add_inf, false);
  const_bool_nodef(check_inf_sub_inf, false);
  const_bool_nodef(check_inf_mul_zero, false);
  const_bool_nodef(check_div_zero, false);
  const_bool_nodef(check_inf_div_inf, false);
  const_bool_nodef(check_inf_mod, false);
  const_bool_nodef(check_sqrt_neg, false);
  const_bool_nodef(has_nan, false);
  const_bool_nodef(has_infinity, false);
  const_bool_nodef(convertible, true);
  const_bool_nodef(fpu_check_inexact, true);
  const_bool_nodef(check_nan_result, true);
  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 // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
struct Extended_Number_Policy {
  const_bool_nodef(check_overflow, true);
  const_bool_nodef(check_inf_add_inf, false);
  const_bool_nodef(check_inf_sub_inf, false);
  const_bool_nodef(check_inf_mul_zero, false);
  const_bool_nodef(check_div_zero, false);
  const_bool_nodef(check_inf_div_inf, false);
  const_bool_nodef(check_inf_mod, false);
  const_bool_nodef(check_sqrt_neg, false);
  const_bool_nodef(has_nan, true);
  const_bool_nodef(has_infinity, true);
  // Do not uncomment the following.
  // The compile time error on conversions is the expected behavior.
  // const_bool_nodef(convertible, false);
  const_bool_nodef(fpu_check_inexact, true);
  const_bool_nodef(check_nan_result, true);
  // Do not uncomment the following.
  // The compile time error is the expected behavior.
  // 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);
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \ingroup PPL_CXX_interface */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
struct WRD_Extended_Number_Policy {
  const_bool_nodef(check_overflow, true);
  const_bool_nodef(check_inf_add_inf, false);
  const_bool_nodef(check_inf_sub_inf, false);
  const_bool_nodef(check_inf_mul_zero, false);
  const_bool_nodef(check_div_zero, false);
  const_bool_nodef(check_inf_div_inf, false);
  const_bool_nodef(check_inf_mod, false);
  const_bool_nodef(check_sqrt_neg, false);
  const_bool_nodef(has_nan, true);
  const_bool_nodef(has_infinity, true);
  // Do not uncomment the following.
  // The compile time error on conversions is the expected behavior.
  // const_bool_nodef(convertible, false);
  const_bool_nodef(fpu_check_inexact, true);
  const_bool_nodef(check_nan_result, false);
  // Do not uncomment the following.
  // The compile time error is the expected behavior.
  // 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);
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! A policy checking for overflows.
/*! \ingroup PPL_CXX_interface */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename T>
struct Check_Overflow_Policy {
  const_bool_nodef(check_overflow, true);
  const_bool_nodef(check_inf_add_inf, false);
  const_bool_nodef(check_inf_sub_inf, false);
  const_bool_nodef(check_inf_mul_zero, false);
  const_bool_nodef(check_div_zero, false);
  const_bool_nodef(check_inf_div_inf, false);
  const_bool_nodef(check_inf_mod, false);
  const_bool_nodef(check_sqrt_neg, false);
  const_bool_nodef(has_nan, std::numeric_limits<T>::has_quiet_NaN);
  const_bool_nodef(has_infinity, std::numeric_limits<T>::has_infinity);
  const_bool_nodef(convertible, true);
  const_bool_nodef(fpu_check_inexact, true);
  const_bool_nodef(check_nan_result, true);
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \ingroup PPL_CXX_interface */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename T, typename Enable = void>
struct Native_Checked_From_Wrapper;

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \ingroup PPL_CXX_interface */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename T>
struct Native_Checked_From_Wrapper<T, typename Enable_If<Is_Native<T>::value>::type> {
  typedef Checked_Number_Transparent_Policy<T> Policy;
  static const T& raw_value(const T& v) {
    return v;
  }
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \ingroup PPL_CXX_interface */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
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();
  }
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \ingroup PPL_CXX_interface */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename T, typename Enable = void>
struct Native_Checked_To_Wrapper;

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \ingroup PPL_CXX_interface */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename T>
struct Native_Checked_To_Wrapper<T, typename Enable_If<Is_Native<T>::value>::type> {
  typedef Check_Overflow_Policy<T> Policy;
  static T& raw_value(T& v) {
    return v;
  }
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \ingroup PPL_CXX_interface */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
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();
  }
};

/*! \ingroup PPL_CXX_interface */
template <typename T>
struct Is_Checked : public False { };

/*! \ingroup PPL_CXX_interface */
template <typename T, typename P>
struct Is_Checked<Checked_Number<T, P> > : public True { };

/*! \ingroup PPL_CXX_interface */
template <typename T>
struct Is_Native_Or_Checked
  : public Bool<Is_Native<T>::value || Is_Checked<T>::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(signed char y, Rounding_Dir dir);

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

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

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

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

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

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

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

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

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

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

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

#if PPL_SUPPORTED_LONG_DOUBLE
  //! Direct initialization from a long double and rounding mode.
  Checked_Number(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 special and rounding mode.
  template <typename From>
  Checked_Number(const From&, Rounding_Dir dir, typename Enable_If<Is_Special<From>::value, bool>::type ignored = false);

  //! 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(signed char y);

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

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

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

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

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

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

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

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

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

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

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

  //! Direct initialization from a long double, default rounding mode.
  Checked_Number(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 special, default rounding mode
  template <typename From>
  Checked_Number(const From&, typename Enable_If<Is_Special<From>::value, bool>::type ignored = false);


  //@} // 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>
  Checked_Number& operator=(const From& 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 Enable_If<Is_Native_Or_Checked<From>::value,
		     Checked_Number<T, Policy>&>::type
  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 Enable_If<Is_Native_Or_Checked<From>::value,
		     Checked_Number<T, Policy>&>::type
  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);

  //! Multiply and assign operator.
  template <typename From>
  typename Enable_If<Is_Native_Or_Checked<From>::value,
		     Checked_Number<T, Policy>&>::type
  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 Enable_If<Is_Native_Or_Checked<From>::value,
		     Checked_Number<T, Policy>&>::type
  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 Enable_If<Is_Native_Or_Checked<From>::value,
		     Checked_Number<T, Policy>& >::type
  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;
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \ingroup PPL_CXX_interface */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename T, typename P>
struct Slow_Copy<Checked_Number<T, P> > : public Bool<Slow_Copy<T>::value> {};

/*! \relates Checked_Number */
template <typename T>
typename Enable_If<Is_Native_Or_Checked<T>::value, bool>::type
is_not_a_number(const T& x);

/*! \relates Checked_Number */
template <typename T>
typename Enable_If<Is_Native_Or_Checked<T>::value, bool>::type
is_minus_infinity(const T& x);

/*! \relates Checked_Number */
template <typename T>
typename Enable_If<Is_Native_Or_Checked<T>::value, bool>::type
is_plus_infinity(const T& x);

/*! \relates Checked_Number */
template <typename T>
typename Enable_If<Is_Native_Or_Checked<T>::value, int>::type
is_infinity(const T& x);

/*! \relates Checked_Number */
template <typename T>
typename Enable_If<Is_Native_Or_Checked<T>::value, bool>::type
is_integer(const T& x);

/*! \relates Checked_Number */
template <typename To, typename From>
typename Enable_If<Is_Native_Or_Checked<To>::value && Is_Special<From>::value, Result>::type
construct(To& to, const From& x, Rounding_Dir dir);

/*! \relates Checked_Number */
template <typename To, typename From>
typename Enable_If<Is_Native_Or_Checked<To>::value && Is_Special<From>::value, Result>::type
assign_r(To& to, const From& x, Rounding_Dir dir);

/*! \relates Checked_Number */
template <typename To>
typename Enable_If<Is_Native_Or_Checked<To>::value, Result>::type
assign_r(To& to, const char* x, Rounding_Dir dir);

/*! \relates Checked_Number */
template <typename To, typename To_Policy>
typename Enable_If<Is_Native_Or_Checked<To>::value, Result>::type
assign_r(To& to, char* x, Rounding_Dir dir);

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

FUNC1(assign_r)
FUNC1(floor_assign_r)
FUNC1(ceil_assign_r)
FUNC1(trunc_assign_r)
FUNC1(neg_assign_r)
FUNC1(abs_assign_r)
FUNC1(sqrt_assign_r)

#undef FUNC1

#define FUNC1(name) \
template <typename To, typename From> \
typename Enable_If<Is_Native_Or_Checked<To>::value \
                   && Is_Native_Or_Checked<From>::value, \
                   Result>::type \
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> \
typename Enable_If<Is_Native_Or_Checked<To>::value \
                   && Is_Native_Or_Checked<From1>::value \
                   && Is_Native_Or_Checked<From2>::value, \
                   Result>::type \
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(idiv_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 To2, typename To3, \
	  typename From1, typename From2> \
typename Enable_If<Is_Native_Or_Checked<To1>::value \
                   && Is_Native_Or_Checked<To2>::value \
                   && Is_Native_Or_Checked<To3>::value \
                   && Is_Native_Or_Checked<From1>::value \
		   && Is_Native_Or_Checked<From2>::value, \
                   Result>::type \
name(To1& to, To2& s, To3& t, \
     const From1& x, const From2& y, \
     Rounding_Dir dir);

FUNC4(gcdext_assign_r)

#undef FUNC4

//! \name Accessor Functions
//@{

//@} // 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>
memory_size_type
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 largest integral value not greater than \p x.
/*! \relates Checked_Number */
template <typename T, typename Policy>
void
floor_assign(Checked_Number<T, Policy>& x);

//! Assigns to \p x largest integral value not greater than \p y.
/*! \relates Checked_Number */
template <typename T, typename Policy>
void
floor_assign(Checked_Number<T, Policy>& x, const Checked_Number<T, Policy>& y);

//! Assigns to \p x smallest integral value not less than \p x.
/*! \relates Checked_Number */
template <typename T, typename Policy>
void
ceil_assign(Checked_Number<T, Policy>& x);

//! Assigns to \p x smallest integral value not less than \p y.
/*! \relates Checked_Number */
template <typename T, typename Policy>
void
ceil_assign(Checked_Number<T, Policy>& x, const Checked_Number<T, Policy>& y);

//! Round \p x to the nearest integer not larger in absolute value.
/*! \relates Checked_Number */
template <typename T, typename Policy>
void
trunc_assign(Checked_Number<T, Policy>& x);

//! Assigns to \p x the value of \p y rounded to the nearest integer not larger in absolute value.
/*! \relates Checked_Number */
template <typename T, typename Policy>
void
trunc_assign(Checked_Number<T, Policy>& x, const Checked_Number<T, Policy>& y);

//! 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 negation of \p y.
/*! \relates Checked_Number */
template <typename T, typename Policy>
void
neg_assign(Checked_Number<T, Policy>& x, const Checked_Number<T, Policy>& y);

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

//! Assigns to \p x the absolute value of \p y.
/*! \relates Checked_Number */
template <typename T, typename Policy>
void
abs_assign(Checked_Number<T, Policy>& x, const Checked_Number<T, Policy>& y);

//! 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,
	      Checked_Number<T, Policy>& s,
	      Checked_Number<T, Policy>& t,
	      const Checked_Number<T, Policy>& y,
	      const Checked_Number<T, Policy>& z);

//! 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 T2>
inline
typename Enable_If<Is_Native_Or_Checked<T1>::value
                   && Is_Native_Or_Checked<T2>::value
                   && (Is_Checked<T1>::value || Is_Checked<T2>::value),
		   bool>::type
operator==(const T1& x, const T2& y);

template <typename T1, typename T2>
inline typename Enable_If<Is_Native_Or_Checked<T1>::value
			  && Is_Native_Or_Checked<T2>::value,
			  bool>::type
equal(const T1& x, const T2& y);

//! Disequality operator.
/*! \relates Checked_Number */
template <typename T1, typename T2>
inline
typename Enable_If<Is_Native_Or_Checked<T1>::value
                   && Is_Native_Or_Checked<T2>::value
                   && (Is_Checked<T1>::value || Is_Checked<T2>::value),
		   bool>::type
operator!=(const T1& x, const T2& y);

template <typename T1, typename T2>
inline typename Enable_If<Is_Native_Or_Checked<T1>::value
			  && Is_Native_Or_Checked<T2>::value,
			  bool>::type
not_equal(const T1& x, const T2& y);

//! Greater than or equal to operator.
/*! \relates Checked_Number */
template <typename T1, typename T2>
inline
typename Enable_If<Is_Native_Or_Checked<T1>::value
                   && Is_Native_Or_Checked<T2>::value
                   && (Is_Checked<T1>::value || Is_Checked<T2>::value),
		   bool>::type
operator>=(const T1& x, const T2& y);

template <typename T1, typename T2>
inline typename Enable_If<Is_Native_Or_Checked<T1>::value
			  && Is_Native_Or_Checked<T2>::value,
			  bool>::type
greater_or_equal(const T1& x, const T2& y);

//! Greater than operator.
/*! \relates Checked_Number */
template <typename T1, typename T2>
inline
typename Enable_If<Is_Native_Or_Checked<T1>::value
                   && Is_Native_Or_Checked<T2>::value
                   && (Is_Checked<T1>::value || Is_Checked<T2>::value),
		   bool>::type
operator>(const T1& x, const T2& y);

template <typename T1, typename T2>
inline typename Enable_If<Is_Native_Or_Checked<T1>::value
			  && Is_Native_Or_Checked<T2>::value,
			  bool>::type
greater_than(const T1& x, const T2& y);

//! Less than or equal to operator.
/*! \relates Checked_Number */
template <typename T1, typename T2>
inline
typename Enable_If<Is_Native_Or_Checked<T1>::value
                   && Is_Native_Or_Checked<T2>::value
                   && (Is_Checked<T1>::value || Is_Checked<T2>::value),
		   bool>::type
operator<=(const T1& x, const T2& y);

template <typename T1, typename T2>
inline typename Enable_If<Is_Native_Or_Checked<T1>::value
			  && Is_Native_Or_Checked<T2>::value,
			  bool>::type
less_or_equal(const T1& x, const T2& y);

//! Less than operator.
/*! \relates Checked_Number */
template <typename T1, typename T2>
inline
typename Enable_If<Is_Native_Or_Checked<T1>::value
                   && Is_Native_Or_Checked<T2>::value
                   && (Is_Checked<T1>::value || Is_Checked<T2>::value),
		   bool>::type
operator<(const T1& x, const T2& y);

template <typename T1, typename T2>
inline typename Enable_If<Is_Native_Or_Checked<T1>::value
			  && Is_Native_Or_Checked<T2>::value,
			  bool>::type
less_than(const T1& x, const T2& 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 From>
inline typename Enable_If<Is_Native_Or_Checked<From>::value, int>::type \
sgn(const From& 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 From1, typename From2>
inline typename Enable_If<Is_Native_Or_Checked<From1>::value
                          && Is_Native_Or_Checked<From2>::value,
                          int>::type
cmp(const From1& x, const From2& y);

//@} // Relational Operators and Comparison Functions

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

/*! \relates Checked_Number */
template <typename T>
typename Enable_If<Is_Native_Or_Checked<T>::value, Result>::type
output(std::ostream& os,
       const T& 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);

//! Ascii dump for native or checked.
template <typename T>
typename Enable_If<Is_Native_Or_Checked<T>::value, void>::type
ascii_dump(std::ostream& s, const T& t);

//! 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 Enable_If<Is_Native_Or_Checked<T>::value, Result>::type
input(T& x, std::istream& is, Rounding_Dir dir);

//! Input operator.
/*! \relates Checked_Number */
template <typename T, typename Policy>
std::istream&
operator>>(std::istream& is, Checked_Number<T, Policy>& x);

//! Ascii load for native or checked.
template <typename T>
typename Enable_If<Is_Native_Or_Checked<T>::value, bool>::type
ascii_load(std::ostream& s, T& t);

//@} // 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();

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

template <typename T, typename Policy>
struct FPU_Related<Checked_Number<T, Policy> > : public FPU_Related<T> {};

template <typename T>
void maybe_reset_fpu_inexact();

template <typename T>
int maybe_check_fpu_inexact();

} // namespace Parma_Polyhedra_Library

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


/* 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 31. */
#include <exception>
#include <gmpxx.h>

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
/*! \brief
  Make sure swap() is specialized when needed.

  This will cause a compile-time error whenever a specialization for \p T
  is beneficial but missing.
*/
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename T>
inline typename Enable_If<Slow_Copy<T>::value, void>::type
swap(T&, T&) {
  PPL_COMPILE_TIME_CHECK(!Slow_Copy<T>::value, "missing swap specialization");
}

/*! \brief
  Declare a local variable named \p id, of type Coefficient, and containing
  an unknown initial value.

  Use of this macro to declare temporaries of type Coefficient results
  in decreased memory allocation overhead and in better locality.
*/
#define PPL_DIRTY_TEMP_COEFFICIENT(id) PPL_DIRTY_TEMP0(Coefficient, id)

#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 // defined(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 make the Grid covering box constructor unique.
*/
struct From_Covering_Box {
};

//! A tag class.
/*! \ingroup PPL_CXX_interface
  Tag class to distinguish those constructors that recycle the data
  structures of their arguments, instead of taking a copy.
*/
struct Recycle_Input {
};

// 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)

#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;

#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_2_PARAM_TEMPLATE_DEFINITIONS(type_symbol1,		\
						type_symbol2,		\
						class_prefix)		\
  template <typename type_symbol1, typename type_symbol2>		\
  void									\
  class_prefix<type_symbol1, type_symbol2>::ascii_dump() const {	\
    ascii_dump(std::cerr);						\
  }									\
									\
  template <typename type_symbol1, typename type_symbol2>		\
  void									\
  class_prefix<type_symbol1, type_symbol2>::print() const {		\
    using namespace IO_Operators;					\
    std::cerr << *this;							\
  }

#define PPL_OUTPUT_3_PARAM_TEMPLATE_DEFINITIONS(type_symbol1,		\
						type_symbol2,		\
						type_symbol3,		\
						class_prefix)		\
  template <typename type_symbol1, typename type_symbol2,		\
            typename type_symbol3>					\
  void									\
  class_prefix<type_symbol1, type_symbol2, type_symbol3>::ascii_dump()	\
    const {								\
    ascii_dump(std::cerr);						\
  }									\
                                                                     	\
    template <typename type_symbol1, typename type_symbol2,		\
              typename type_symbol3>					\
    void								\
    class_prefix<type_symbol1, type_symbol2, type_symbol3>::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;	\
  }

template <typename T, long long v, typename Enable = void>
struct Fit : public False {
};

template <typename T, long long v>
struct Fit<T, v, typename Enable_If<C_Integer<T>::value>::type>  {
  enum {
    value = (v >= static_cast<long long>(C_Integer<T>::min)
             && v <= static_cast<long long>(C_Integer<T>::max))
  };
};

template <typename T, long long v>
struct TConstant {
  static const T value = v;
};


template <typename T, long long v>
const T TConstant<T, v>::value;

template <typename T, long long v, bool prefer_signed = true,
	  typename Enable = void>
struct Constant_ : public TConstant<T, v> {
};

template <typename T, long long v, bool prefer_signed>
struct Constant_<T, v, prefer_signed,
		 typename Enable_If<(Fit<typename C_Integer<T>::smaller_signed_type, v>::value
				     && (prefer_signed ||
					 !Fit<typename C_Integer<T>::smaller_unsigned_type, v>::value))>::type>
  : public Constant_<typename C_Integer<T>::smaller_signed_type, v, prefer_signed> {
};

template <typename T, long long v, bool prefer_signed>
struct Constant_<T, v, prefer_signed,
		 typename Enable_If<(Fit<typename C_Integer<T>::smaller_unsigned_type, v>::value
				     && (!prefer_signed ||
					 !Fit<typename C_Integer<T>::smaller_signed_type, v>::value))>::type>
  : public Constant_<typename C_Integer<T>::smaller_unsigned_type, v, prefer_signed> {
};

template <long long v, bool prefer_signed = true>
struct Constant : public Constant_<long long, v, prefer_signed> {
};

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

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \brief
  For native types, returns the total size in bytes of the memory
  occupied by the type of the (unused) parameter, i.e., 0.
*/
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename T>
typename Enable_If<Is_Native<T>::value, memory_size_type>::type
total_memory_in_bytes(const T&);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \brief
  For native types, returns the size in bytes of the memory managed
  by the type of the (unused) parameter, i.e., 0.
*/
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename T>
typename Enable_If<Is_Native<T>::value, memory_size_type>::type
external_memory_in_bytes(const T&);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Returns the total size in bytes of the memory occupied by \p x.
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
memory_size_type
total_memory_in_bytes(const mpz_class& x);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Returns the size in bytes of the memory managed by \p x.
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
memory_size_type
external_memory_in_bytes(const mpz_class& x);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Returns the total size in bytes of the memory occupied by \p x.
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
memory_size_type
total_memory_in_bytes(const mpq_class& x);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Returns the size in bytes of the memory managed by \p x.
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
memory_size_type
external_memory_in_bytes(const mpq_class& x);

//@} // Memory Size Inspection Functions


template <typename T, typename Enable = void>
struct Has_OK : public False { };

template <typename T>
struct Has_OK<T, typename Enable_If_Is<bool (T::*)() const, &T::OK>::type>
  : public True {
};

template <typename T>
inline typename Enable_If<Has_OK<T>::value, bool>::type
f_OK(const T& to) {
  return to.OK();
}

#define FOK(T) inline bool f_OK(const T&) { return true; }

FOK(char)
FOK(signed char)
FOK(unsigned char)
FOK(signed short)
FOK(unsigned short)
FOK(signed int)
FOK(unsigned int)
FOK(signed long)
FOK(unsigned long)
FOK(signed long long)
FOK(unsigned long long)
FOK(float)
FOK(double)
FOK(long double)
FOK(mpz_class)
FOK(mpq_class)

} // namespace Parma_Polyhedra_Library

/* Automatically generated from PPL source file ../src/globals.inlines.hh line 1. */
/* Implementation of global objects: inline functions.
*/


#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;
}

template <typename T>
inline typename
Enable_If<Is_Native<T>::value, memory_size_type>::type
external_memory_in_bytes(const T&) {
  return 0;
}

template <typename T>
inline typename
Enable_If<Is_Native<T>::value, memory_size_type>::type
total_memory_in_bytes(const T&) {
  return sizeof(T);
}

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

inline memory_size_type
total_memory_in_bytes(const mpz_class& x) {
  return sizeof(x) + external_memory_in_bytes(x);
}

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());
}

inline memory_size_type
total_memory_in_bytes(const mpq_class& x) {
  return sizeof(x) + external_memory_in_bytes(x);
}

} // namespace Parma_Polyhedra_Library

/* Automatically generated from PPL source file ../src/globals.defs.hh line 387. */

/* Automatically generated from PPL source file ../src/Checked_Number.inlines.hh line 27. */
#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 & ROUND_FPU_CHECK_INEXACT;
#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?

    // To solve this we need to clarify if ROUND_NOT_NEEDED is
    // specified to grant library that the result will be exact _and_
    // not overflowing or the result will be exact _or_ overflowling.
    assert(r == V_EQ);
#else
    return V_EQ;
#endif
  }
  return r;
}


template <typename T>
inline void
Checked_Number_Transparent_Policy<T>::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);
}

inline void
WRD_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, 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, Checked_Number_Transparent_Policy<type> >	\
		  (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, Checked_Number_Transparent_Policy<type> >	\
		  (v, x, rounding_dir(dir)),				\
		  dir));						\
}

#define PPL_COND_0(...)
#define PPL_COND_1(...) __VA_ARGS__
#define PPL_COND_(if, ...) PPL_COND_##if(__VA_ARGS__)
#define PPL_COND(if, ...) PPL_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)
PPL_COND(PPL_SUPPORTED_FLOAT, DEF_CTOR(float))
PPL_COND(PPL_SUPPORTED_DOUBLE, DEF_CTOR(double))
PPL_COND(PPL_SUPPORTED_LONG_DOUBLE, DEF_CTOR(long double))
DEF_CTOR(mpq_class&)
DEF_CTOR(mpz_class&)

#undef DEF_CTOR

#undef PPL_COND
#undef PPL_COND_
#undef PPL_COND_1
#undef PPL_COND_0

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>
template <typename From>
inline
Checked_Number<T, Policy>::Checked_Number(const From&, Rounding_Dir dir, typename Enable_If<Is_Special<From>::value, bool>::type) {
  Policy::handle_result(check_result(Checked::assign_special<Policy>(v,
							    From::code,
							    rounding_dir(dir)),
				     dir));
}

template <typename T, typename Policy>
template <typename From>
inline
Checked_Number<T, Policy>::Checked_Number(const From&, typename Enable_If<Is_Special<From>::value, bool>::type) {
  Rounding_Dir dir = Policy::ROUND_DEFAULT_CONSTRUCTOR;
  Policy::handle_result(check_result(Checked::assign_special<Policy>(v,
							    From::code,
							    rounding_dir(dir)),
				     dir));
}

template <typename To, typename From>
inline typename Enable_If<Is_Native_Or_Checked<To>::value && Is_Special<From>::value, Result>::type
assign_r(To& to, const From&, Rounding_Dir dir) {
  return check_result(Checked::assign_special<typename Native_Checked_To_Wrapper<To>
		      ::Policy>(Native_Checked_To_Wrapper<To>::raw_value(to),
				From::code,
				rounding_dir(dir)),
		      dir);
}

template <typename To, typename From>
inline typename Enable_If<Is_Native_Or_Checked<To>::value && Is_Special<From>::value, Result>::type
construct(To& to, const From&, Rounding_Dir dir) {
  return check_result(Checked::construct_special<typename Native_Checked_To_Wrapper<To>
		      ::Policy>(Native_Checked_To_Wrapper<To>::raw_value(to),
				From::code,
				rounding_dir(dir)),
		      dir);
}

template <typename T>
inline typename Enable_If<Is_Native_Or_Checked<T>::value, bool>::type
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 typename Enable_If<Is_Native_Or_Checked<T>::value, bool>::type
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 typename Enable_If<Is_Native_Or_Checked<T>::value, int>::type
is_infinity(const T& x) {
  return is_minus_infinity(x) ? -1 : is_plus_infinity(x) ? 1 : 0;
}

template <typename T>
inline typename Enable_If<Is_Native_Or_Checked<T>::value, bool>::type
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 typename Enable_If<Is_Native_Or_Checked<T>::value, bool>::type
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 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 external_memory_in_bytes(x.raw_value());
}


/*! \relates Checked_Number */
template <typename To>
inline typename Enable_If<Is_Native_Or_Checked<To>::value, Result>::type
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 typename Enable_If<Is_Native_Or_Checked<To>::value               \
                          && Is_Native_Or_Checked<From>::value,         \
                          Result>::type                                 \
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(floor_assign_r, floor_ext)
FUNC1(ceil_assign_r, ceil_ext)
FUNC1(trunc_assign_r, trunc_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 typename Enable_If<Is_Native_Or_Checked<To>::value		\
                          && Is_Native_Or_Checked<From>::value,         \
                          Result>::type					\
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 typename Enable_If<Is_Native_Or_Checked<To>::value		\
                          && Is_Native_Or_Checked<From1>::value         \
                          && Is_Native_Or_Checked<From2>::value,        \
                          Result>::type					\
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(idiv_assign_r, idiv_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 To2,							\
	  typename To3,							\
          typename From1,						\
          typename From2>						\
inline typename Enable_If<Is_Native_Or_Checked<To1>::value		\
                          && Is_Native_Or_Checked<To2>::value           \
                          && Is_Native_Or_Checked<To3>::value           \
                          && Is_Native_Or_Checked<From1>::value         \
                          && Is_Native_Or_Checked<From2>::value,        \
                          Result>::type					\
name(To1& to, To2& s, To3& t, const From1& x, const From2& y,		\
     Rounding_Dir dir) {						\
  return								\
    check_result							\
    (Checked::func<typename Native_Checked_To_Wrapper<To1>::Policy,	\
                   typename Native_Checked_To_Wrapper<To2>::Policy,	\
                   typename Native_Checked_To_Wrapper<To3>::Policy,	\
                   typename Native_Checked_From_Wrapper<From1>::Policy,	\
                   typename Native_Checked_From_Wrapper<From2>::Policy>	\
     (Native_Checked_To_Wrapper<To1>::raw_value(to),			\
      Native_Checked_To_Wrapper<To2>::raw_value(s),			\
      Native_Checked_To_Wrapper<To3>::raw_value(t),			\
      Native_Checked_From_Wrapper<From1>::raw_value(x),			\
      Native_Checked_From_Wrapper<From2>::raw_value(y),			\
      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

template <typename T, typename Policy>
inline Checked_Number<T, Policy>&
Checked_Number<T, Policy>::operator=(const Checked_Number<T, Policy>& y) {
  Checked::copy<Policy, Policy>(v, y.raw_value());
  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;
}

#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> \
inline typename Enable_If<Is_Native_Or_Checked<From>::value, \
                          Checked_Number<T, Policy>& >::type \
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(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; \
} \
template <typename Type, typename T, typename Policy>	\
inline \
typename Enable_If<Is_Native<Type>::value, Checked_Number<T, Policy> >::type \
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, typename Type>	\
inline \
typename Enable_If<Is_Native<Type>::value, Checked_Number<T, Policy> >::type \
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; \
}

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

#define DEF_COMPARE(f, fun)						\
template <typename T1, typename T2>					\
inline									\
typename Enable_If<Is_Native_Or_Checked<T1>::value                      \
                   && Is_Native_Or_Checked<T2>::value                   \
                   && (Is_Checked<T1>::value || Is_Checked<T2>::value),	\
		   bool>::type						\
f(const T1& x, const T2& y) {						\
  return Checked::fun<typename Native_Checked_From_Wrapper<T1>::Policy,	\
    		      typename Native_Checked_From_Wrapper<T2>::Policy>	\
    (Native_Checked_From_Wrapper<T1>::raw_value(x),			\
     Native_Checked_From_Wrapper<T2>::raw_value(y));			\
}

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

#define DEF_COMPARE(f, fun)						\
template <typename T1, typename T2>					\
inline typename Enable_If<Is_Native_Or_Checked<T1>::value		\
			  && Is_Native_Or_Checked<T2>::value,		\
                          bool>::type					\
f(const T1& x, const T2& y) {						\
  return Checked::fun<typename Native_Checked_From_Wrapper<T1>::Policy,	\
    		      typename Native_Checked_From_Wrapper<T2>::Policy>	\
    (Native_Checked_From_Wrapper<T1>::raw_value(x),			\
     Native_Checked_From_Wrapper<T2>::raw_value(y));			\
}

DEF_COMPARE(equal, eq_ext)
DEF_COMPARE(not_equal, ne_ext)
DEF_COMPARE(greater_or_equal, ge_ext)
DEF_COMPARE(greater_than, gt_ext)
DEF_COMPARE(less_or_equal, le_ext)
DEF_COMPARE(less_than, lt_ext)

#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 PPL_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 PPL_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 PPL_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 PPL_DEF_ASSIGN_FUN5_5(f, fun)					\
template <typename T, typename Policy>					\
inline void								\
f(Checked_Number<T, Policy>& x,						\
  Checked_Number<T, Policy>& s, Checked_Number<T, Policy>& t,		\
  const Checked_Number<T, Policy>& y,					\
  const Checked_Number<T, Policy>& z) {					\
  Policy::handle_result(fun(x, s, t, y, z, Policy::ROUND_DEFAULT_FUNCTION)); \
}

PPL_DEF_ASSIGN_FUN2_2(sqrt_assign, sqrt_assign_r)

PPL_DEF_ASSIGN_FUN2_1(floor_assign, floor_assign_r)
PPL_DEF_ASSIGN_FUN2_2(floor_assign, floor_assign_r)

PPL_DEF_ASSIGN_FUN2_1(ceil_assign, ceil_assign_r)
PPL_DEF_ASSIGN_FUN2_2(ceil_assign, ceil_assign_r)

PPL_DEF_ASSIGN_FUN2_1(trunc_assign, trunc_assign_r)
PPL_DEF_ASSIGN_FUN2_2(trunc_assign, trunc_assign_r)

PPL_DEF_ASSIGN_FUN2_1(neg_assign, neg_assign_r)
PPL_DEF_ASSIGN_FUN2_2(neg_assign, neg_assign_r)

PPL_DEF_ASSIGN_FUN2_1(abs_assign, abs_assign_r)
PPL_DEF_ASSIGN_FUN2_2(abs_assign, abs_assign_r)

PPL_DEF_ASSIGN_FUN3_3(add_mul_assign, add_mul_assign_r)

PPL_DEF_ASSIGN_FUN3_3(sub_mul_assign, sub_mul_assign_r)

PPL_DEF_ASSIGN_FUN3_3(rem_assign, rem_assign_r)

PPL_DEF_ASSIGN_FUN3_3(gcd_assign, gcd_assign_r)

PPL_DEF_ASSIGN_FUN5_5(gcdext_assign, gcdext_assign_r)

PPL_DEF_ASSIGN_FUN3_3(lcm_assign, lcm_assign_r)

#undef PPL_DEF_ASSIGN_FUN2_1
#undef PPL_DEF_ASSIGN_FUN2_2
#undef PPL_DEF_ASSIGN_FUN3_2
#undef PPL_DEF_ASSIGN_FUN3_3
#undef PPL_DEF_ASSIGN_FUN5_5

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 From>
inline typename Enable_If<Is_Native_Or_Checked<From>::value, int>::type
sgn(const From& x) {
  Result r = Checked::sgn_ext<typename Native_Checked_From_Wrapper<From>::Policy>(Native_Checked_From_Wrapper<From>::raw_value(x));
  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 From1, typename From2>
inline typename Enable_If<Is_Native_Or_Checked<From1>::value
                          && Is_Native_Or_Checked<From2>::value,
                          int>::type
cmp(const From1& x, const From2& y) {
  Result r
    = Checked::cmp_ext<typename Native_Checked_From_Wrapper<From1>::Policy,
                       typename Native_Checked_From_Wrapper<From2>::Policy>
                 (Native_Checked_From_Wrapper<From1>::raw_value(x),
		  Native_Checked_From_Wrapper<From2>::raw_value(y));
  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 Enable_If<Is_Native_Or_Checked<T>::value, Result>::type
output(std::ostream& os, const T& x,
       const Numeric_Format& fmt, Rounding_Dir dir) {
  return check_result(Checked::output_ext<typename Native_Checked_From_Wrapper<T>::Policy>
		      (os,
		       Native_Checked_From_Wrapper<T>::raw_value(x),
		       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 Enable_If<Is_Native_Or_Checked<T>::value, Result>::type
input(T& x, std::istream& is, Rounding_Dir dir) {
  return check_result(Checked::input_ext<typename Native_Checked_To_Wrapper<T>::Policy>
		      (Native_Checked_To_Wrapper<T>::raw_value(x),
		       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;
}

/*! \relates Checked_Number */
template <typename T, typename Policy>
inline void
swap(Checked_Number<T, Policy>& x, Checked_Number<T, Policy>& y) {
  using std::swap;
  swap(x.raw_value(), y.raw_value());
}

template <typename T>
inline void
maybe_reset_fpu_inexact() {
  if (FPU_Related<T>::value)
    return fpu_reset_inexact();
}

template <typename T>
inline int
maybe_check_fpu_inexact() {
  if (FPU_Related<T>::value)
    return fpu_check_inexact();
  else
    return 0;
}

} // 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/checked_numeric_limits.hh line 28. */
#include <limits>

namespace std {

using namespace Parma_Polyhedra_Library;

#define PPL_SPECIALIZE_LIMITS_INT(T)					\
/*! \brief Partial specialization of std::numeric_limits. */		\
template <typename Policy>						\
 class numeric_limits<Checked_Number<T, Policy> >                       \
  : public numeric_limits<T> {						\
 private:								\
  typedef Checked_Number<T, Policy> Type;                               \
									\
 public:								\
  static const bool has_infinity = Policy::has_infinity;		\
  static const bool has_quiet_NaN =  Policy::has_nan;                   \
                                                                        \
  static Type min() {							\
    return Checked::Extended_Int<Policy, T>::min;                       \
  }									\
                                                                        \
  static Type max() {							\
    return Checked::Extended_Int<Policy, T>::max;                       \
  }									\
									\
  static Type infinity() {						\
    return								\
      Policy::has_infinity						\
      ? PLUS_INFINITY                                                   \
      : static_cast<Type>(0);						\
  }									\
									\
  static Type quiet_NaN() {						\
    return								\
      Policy::has_nan                                                   \
      ? 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<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 // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename Policy>
class
numeric_limits<Checked_Number<mpz_class, Policy> >
  : public numeric_limits<mpz_class> {
private:
  typedef Checked_Number<mpz_class, Policy> Type;

public:
  static const bool has_infinity = Policy::has_infinity;
  static const bool has_quiet_NaN =  Policy::has_nan;

  static Type infinity() {
    return
      Policy::has_infinity
      ? PLUS_INFINITY
      : static_cast<Type>(0);
  }

  static Type quiet_NaN() {
    return
      Policy::has_nan
      ? NOT_A_NUMBER
      : static_cast<Type>(0);
  }
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Partial specialization of std::numeric_limits.
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename Policy>
class
numeric_limits<Checked_Number<mpq_class, Policy> >
: public numeric_limits<mpq_class> {
private:
  typedef Checked_Number<mpq_class, Policy> Type;

public:
  static const bool has_infinity = Policy::has_infinity;
  static const bool has_quiet_NaN =  Policy::has_nan;

  static Type infinity() {
    return
      Policy::has_infinity
      ? PLUS_INFINITY
      : static_cast<Type>(0);
  }

  static Type quiet_NaN() {
    return
      Policy::has_nan
      ? NOT_A_NUMBER
      : static_cast<Type>(0);
  }
};

} // namespace std

/* Automatically generated from PPL source file ../src/Checked_Number.templates.hh line 1. */
/* Checked_Number class implementation: non-inline template functions.
*/


#include <cassert>
#include <iomanip>
#include <limits>

namespace Parma_Polyhedra_Library {

template <typename T>
typename Enable_If<Is_Native_Or_Checked<T>::value, void>::type
ascii_dump(std::ostream& s, const T& t) {
  if (std::numeric_limits<T>::is_exact)
    // An exact datatype: pretty printer is accurate.
    s << t;
  else {
    // An inexact datatype (probably floating point):
    // first dump its hexadecimal representation ...
    const std::ios_base::fmtflags old_flags = s.flags();
    s << std::hex;
    const unsigned char* p = reinterpret_cast<const unsigned char*>(&t);
    for (unsigned i = 0; i < sizeof(T); ++i) {
      s << std::setw(2) << std::setfill('0');
      s << static_cast<unsigned>(p[i]);
    }
    s.flags(old_flags);
    // ... and then pretty print it for readability.
    s << " (" << t << ")";
  }
}

template <typename T>
typename Enable_If<Is_Native_Or_Checked<T>::value, bool>::type
ascii_load(std::istream& s, T& t) {
  if (std::numeric_limits<T>::is_exact)
    // An exact datatype: input from pretty printed version is accurate.
    return (s >> t);
  else {
    // An inexact datatype (probably floating point):
    // first load its hexadecimal representation ...
    std::string str;
    if (!(s >> str) || str.size() != 2*sizeof(T))
      return false;
    unsigned char* p = reinterpret_cast<unsigned char*>(&t);
    // CHECKME: any (portable) simpler way?
    for (unsigned i = 0; i < sizeof(T); ++i) {
      unsigned byte_value = 0;
      for (unsigned j = 0; j < 2; ++j) {
        byte_value <<= 4;
        unsigned half_byte_value;
        // Interpret single hex character.
        switch (str[2*i+j]) {
        case '0':
          half_byte_value = 0;
          break;
        case '1':
          half_byte_value = 1;
          break;
        case '2':
          half_byte_value = 2;
          break;
        case '3':
          half_byte_value = 3;
          break;
        case '4':
          half_byte_value = 4;
          break;
        case '5':
          half_byte_value = 5;
          break;
        case '6':
          half_byte_value = 6;
          break;
        case '7':
          half_byte_value = 7;
          break;
        case '8':
          half_byte_value = 8;
          break;
        case '9':
          half_byte_value = 9;
          break;
        case 'A':
        case 'a':
          half_byte_value = 10;
          break;
        case 'B':
        case 'b':
          half_byte_value = 11;
          break;
        case 'C':
        case 'c':
          half_byte_value = 12;
          break;
        case 'D':
        case 'd':
          half_byte_value = 13;
          break;
        case 'E':
        case 'e':
          half_byte_value = 14;
          break;
        case 'F':
        case 'f':
          half_byte_value = 15;
          break;
        default:
          return false;
        }
        byte_value += half_byte_value;
      }
      assert(byte_value <= 255);
      p[i] = static_cast<unsigned char>(byte_value);
    }
    // ... then read and discard pretty printed value.
    if (!(s >> str))
      return false;
    const unsigned sz = str.size();
    return sz > 2 && str[0] == '(' && str[sz-1] == ')';
  }
}

} // namespace Parma_Polyhedra_Library

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

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

#if defined(PPL_CHECKED_INTEGERS) || defined(PPL_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 // defined(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 // defined(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 // defined(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 // defined(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(PPL_CHECKED_INTEGERS) || defined(PPL_NATIVE_INTEGERS)

#ifdef PPL_GMP_INTEGERS
/* 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>
/* Automatically generated from PPL source file ../src/GMP_Integer.types.hh line 18. */

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 // defined(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 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 PPL_COEFFICIENT_TYPE Coefficient;

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! An alias for easily naming the coefficient traits.
/*! \ingroup PPL_CXX_interface */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
typedef Coefficient_traits_template<Coefficient> Coefficient_traits;

} // 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/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/Congruence.types.hh line 1. */


namespace Parma_Polyhedra_Library {

class Congruence;

}

/* 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/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 // defined(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 c and \p g and assigns it to \p z.
  static void assign(Coefficient& z,
		     const Constraint& c, const Grid_Generator& g);
  //! 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);
  //! Returns the sign of the scalar product between \p c and \p g.
  static int sign(const Constraint& c, const Grid_Generator& g);

  /*! \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 c,
  //! where the inhomogeneous terms are ignored,
  //! and assigns the result to \p z.
  static void homogeneous_assign(Coefficient& z,
				 const Grid_Generator& g, const Constraint& c);
  //! \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);
  //! \brief
  //! Returns the sign of the \e homogeneous scalar product of \p g and \p c,
  //! where the inhomogeneous terms are ignored,
  static int homogeneous_sign(const Grid_Generator& g, const Constraint& c);
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Scalar product sign function object depending on topology.
/*! \ingroup PPL_CXX_interface */
#endif // defined(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/Linear_Row.defs.hh line 1. */
/* Linear_Row 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.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/Coefficient.defs.hh line 1. */
/* Coefficient class declaration.
*/


/* Automatically generated from PPL source file ../src/Coefficient.defs.hh line 27. */
#include <iosfwd>

#if defined(PPL_CHECKED_INTEGERS) || defined(PPL_NATIVE_INTEGERS)
/* Automatically generated from PPL source file ../src/Coefficient.defs.hh line 32. */
#endif

#ifdef PPL_GMP_INTEGERS
/* 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
//@{

#ifndef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Returns the total size in bytes of the memory occupied by \p x.
/*! \relates GMP_Integer */
#endif // !defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
memory_size_type total_memory_in_bytes(const GMP_Integer& x);

#ifndef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Returns the size in bytes of the memory managed by \p x.
/*! \relates GMP_Integer */
#endif // !defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
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 its absolute value.
/*! \relates GMP_Integer */
void abs_assign(GMP_Integer& x);

//! Assigns to \p x the absolute value of \p y.
/*! \relates GMP_Integer */
void abs_assign(GMP_Integer& x, const GMP_Integer& y);

//! Assigns to \p x the remainder of the division of \p y by \p z.
/*! \relates GMP_Integer */
void rem_assign(GMP_Integer& x,
		const GMP_Integer& y, const GMP_Integer& z);

//! 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, GMP_Integer& s, GMP_Integer& t,
		   const GMP_Integer& y, const GMP_Integer& z);

//! 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

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


#include <cassert>

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
abs_assign(GMP_Integer& x) {
  mpz_abs(x.get_mpz_t(), x.get_mpz_t());
}

inline void
abs_assign(GMP_Integer& x, const GMP_Integer& y) {
  mpz_abs(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
rem_assign(GMP_Integer& x, const GMP_Integer& y, const GMP_Integer& z) {
  mpz_tdiv_r(x.get_mpz_t(), y.get_mpz_t(), z.get_mpz_t());
}

inline void
gcdext_assign(GMP_Integer& x, GMP_Integer& s, GMP_Integer& t,
	      const GMP_Integer& y, const GMP_Integer& z) {
  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;
}

} // namespace Parma_Polyhedra_Library

/* Automatically generated from PPL source file ../src/GMP_Integer.defs.hh line 141. */

/* Automatically generated from PPL source file ../src/Coefficient.defs.hh line 36. */
#endif

namespace Parma_Polyhedra_Library {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Initializes the Coefficient constants.
#endif
void Coefficient_constants_initialize();

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Finalizes the Coefficient constants.
#endif
void Coefficient_constants_finalize();

//! Returns a const reference to a Coefficient with value 0.
Coefficient_traits::const_reference Coefficient_zero();

//! Returns a const reference to a Coefficient with value 1.
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 {

#if defined(PPL_CHECKED_INTEGERS) || defined(PPL_NATIVE_INTEGERS)
inline Coefficient_traits::const_reference
Coefficient_zero() {
  // FIXME: is there a way to avoid this static variable?
  static Coefficient zero(0);
  return zero;
}

inline Coefficient_traits::const_reference
Coefficient_one() {
  // FIXME: is there a way to avoid this static variable?
  static Coefficient one(1);
  return one;
}
#endif

#ifdef PPL_GMP_INTEGERS
inline Coefficient_traits::const_reference
Coefficient_zero() {
  extern const Coefficient* Coefficient_zero_p;
  return *Coefficient_zero_p;
}

inline Coefficient_traits::const_reference
Coefficient_one() {
  extern const Coefficient* Coefficient_one_p;
  assert(*Coefficient_one_p != 0);
  return *Coefficient_one_p;
}
#endif

} // namespace Parma_Polyhedra_Library

/* Automatically generated from PPL source file ../src/Coefficient.defs.hh line 59. */

/* Automatically generated from PPL source file ../src/Row.defs.hh line 29. */
#include <vector>
#include <limits>

#ifndef PPL_ROW_EXTRA_DEBUG
#ifdef PPL_ABI_BREAKING_EXTRA_DEBUG
#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*!
  \brief
  Enables extra debugging information for class Row.

  \ingroup PPL_CXX_interface
  When <CODE>PPL_ROW_EXTRA_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 // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
#define PPL_ROW_EXTRA_DEBUG 1
#else // !defined(PPL_ABI_BREAKING_EXTRA_DEBUG)
#define PPL_ROW_EXTRA_DEBUG 0
#endif // !defined(PPL_ABI_BREAKING_EXTRA_DEBUG)
#endif // !defined(PPL_ROW_EXTRA_DEBUG)

#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 // defined(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 PPL_ROW_EXTRA_DEBUG
  //! The capacity of \p impl (only available during debugging).
  dimension_type capacity_;
#endif // PPL_ROW_EXTRA_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 // defined(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 // defined(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

  /*! \brief
    Loads from \p s an ASCII representation (as produced by
    ascii_dump(std::ostream&) const) and sets \p *this accordingly.
    Returns <CODE>true</CODE> if successful, <CODE>false</CODE> otherwise.
  */
  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() const;

  /*! \brief
    Checks if all the invariants are satisfied and that the actual
    size and capacity match the values provided as arguments.
  */
  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 PPL_ROW_EXTRA_DEBUG
  //! Returns the capacity of the row (only available during debugging).
  dimension_type capacity() const;
#endif // PPL_ROW_EXTRA_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 // defined(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 // defined(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 // defined(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 !PPL_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/math_utilities.defs.hh line 1. */
/* Declarations of some math utility functions.
*/


/* Automatically generated from PPL source file ../src/math_utilities.defs.hh line 28. */
#include <gmpxx.h>

namespace Parma_Polyhedra_Library {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Extract the numerator and denominator components of \p from.
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename T, typename Policy>
void
numer_denom(const Checked_Number<T, Policy>& from,
	    Coefficient& num, Coefficient& den);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Divides \p x by \p y into \p to, rounding the result towards plus infinity.
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename T, typename Policy>
void
div_round_up(Checked_Number<T, Policy>& to,
	     Coefficient_traits::const_reference x,
	     Coefficient_traits::const_reference y);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Assigns to \p x the minimum between \p x and \p y.
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename N>
void
min_assign(N& x, const N& y);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Assigns to \p x the maximum between \p x and \p y.
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename N>
void
max_assign(N& x, const N& y);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Returns <CODE>true</CODE> if and only if \p x is an even number.
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename T, typename Policy>
bool
is_even(const Checked_Number<T, Policy>& x);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Returns <CODE>true</CODE> if and only if \f$x = -y\f$.
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename T, typename Policy>
bool
is_additive_inverse(const Checked_Number<T, Policy>& x,
		    const Checked_Number<T, Policy>& y);

#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 <CODE>true</CODE> if and only if \p x is in canonical form.
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
bool
is_canonical(const mpq_class& x);

#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);

} // namespace Parma_Polyhedra_Library

/* Automatically generated from PPL source file ../src/math_utilities.inlines.hh line 1. */
/* Implementation of some math utility functions: inline functions.
*/


/* Automatically generated from PPL source file ../src/math_utilities.inlines.hh line 27. */
#include <limits>
#include <cassert>

namespace Parma_Polyhedra_Library {

inline void
normalize2(Coefficient_traits::const_reference x,
	   Coefficient_traits::const_reference y,
	   Coefficient& nx, Coefficient& ny) {
  PPL_DIRTY_TEMP_COEFFICIENT(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);
}

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));
  PPL_DIRTY_TEMP0(mpq_class, q);
  assign_r(q, from, ROUND_NOT_NEEDED);
  num = q.get_num();
  den = q.get_den();
}

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) {
  PPL_DIRTY_TEMP0(mpq_class, qx);
  PPL_DIRTY_TEMP0(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);
}

template <typename N>
inline void
min_assign(N& x, const N& y) {
  if (x > y)
    x = y;
}

template <typename N>
inline void
max_assign(N& x, const N& y) {
  if (x < y)
    x = y;
}

template <typename T, typename Policy>
inline bool
is_even(const Checked_Number<T, Policy>& x) {
  Checked_Number<T, Policy> half_x;
  return div2exp_assign_r(half_x, x, 1, ROUND_DIRECT) == V_EQ
    && is_integer(half_x);
}

template <typename T, typename Policy>
inline bool
is_additive_inverse(const Checked_Number<T, Policy>& x,
		    const Checked_Number<T, Policy>& y) {
  Checked_Number<T, Policy> negated_x;
  return neg_assign_r(negated_x, x, ROUND_DIRECT) == V_EQ
    && negated_x == y;
}

inline bool
is_canonical(const mpq_class& x) {
  if (x.get_den() <= 0)
    return false;
  PPL_DIRTY_TEMP0(mpq_class, temp);
  temp = x;
  temp.canonicalize();
  return temp.get_num() == x.get_num();
}

} // namespace Parma_Polyhedra_Library

/* Automatically generated from PPL source file ../src/math_utilities.defs.hh line 109. */

/* Automatically generated from PPL source file ../src/Row.inlines.hh line 27. */
#include <cassert>
#include <cstddef>
#include <limits>
#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 PPL_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 std::numeric_limits<size_t>::max() / 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 !PPL_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 PPL_ROW_EXTRA_DEBUG
inline dimension_type
Row::capacity() const {
  return capacity_;
}
#endif

inline
Row_Impl_Handler::Row_Impl_Handler()
  : impl(0) {
#if PPL_ROW_EXTRA_DEBUG
  capacity_ = 0;
#endif
}

inline
Row_Impl_Handler::~Row_Impl_Handler() {
  delete impl;
}

inline
Row::Row()
  : Row_Impl_Handler() {
}

inline void
Row::allocate(
#if PPL_CXX_SUPPORTS_FLEXIBLE_ARRAYS
	       const
#endif
	       dimension_type capacity,
	       const Flags f) {
  assert(capacity <= max_size());
#if !PPL_CXX_SUPPORTS_FLEXIBLE_ARRAYS
  if (capacity == 0)
    ++capacity;
#endif
  assert(impl == 0);
  impl = new (capacity) Impl(f);
#if PPL_ROW_EXTRA_DEBUG
  assert(capacity_ == 0);
  capacity_ = capacity;
#endif
}

inline void
Row::expand_within_capacity(const dimension_type new_size) {
  assert(impl);
#if PPL_ROW_EXTRA_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 PPL_ROW_EXTRA_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 PPL_ROW_EXTRA_DEBUG
  std::swap(capacity_, y.capacity_);
#endif
}

inline void
Row::assign(Row& y) {
  impl = y.impl;
#if PPL_ROW_EXTRA_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 PPL_ROW_EXTRA_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 505. */

/* 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 // defined(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 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 // defined(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 // defined(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

    /*! \brief
      Loads from \p s an ASCII representation (as produced by
      ascii_dump(std::ostream&) const) and sets \p *this accordingly.
      Returns <CODE>true</CODE> if successful, <CODE>false</CODE> otherwise.
    */
    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

  /*! \brief
    Loads from \p s an ASCII representation (as produced by
    ascii_dump(std::ostream&) const) 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;

  /*! \brief
    Checks if all the invariants are satisfied and that the actual
    size and capacity match the values provided as arguments.
  */
  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 // defined(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 // defined(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 // defined(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 463. */

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


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


/* 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/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 <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. */

/* 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/Congruence_System.types.hh line 1. */


namespace Parma_Polyhedra_Library {

class Congruence_System;

}

/* 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/Polyhedron.types.hh line 1. */


namespace Parma_Polyhedra_Library {

class 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/Linear_Expression.defs.hh line 41. */
#include <cstddef>

namespace Parma_Polyhedra_Library {
// Put them in the namespace here to declare them friend later.

//! 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.
  /*!
    \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);

  /*! \brief
    Builds the linear expression corresponding to grid generator \p g
    (for points, parameters and lines the divisor is not copied).

    Given the grid generator
    \f$g = (\frac{a_0}{d}, \ldots, \frac{a_{n-1}}{d})^\transpose\f$
    this builds the linear expression \f$\sum_{i=0}^{n-1} a_i x_i\f$.
    The inhomogeneous term of the linear expression is always 0.
  */
  explicit Linear_Expression(const Grid_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;

  //! Initializes the class.
  static void initialize();

  //! Finalizes the class.
  static void finalize();

  //! 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;

  PPL_OUTPUT_DECLARATIONS

  /*! \brief
    Loads from \p s an ASCII representation (as produced by
    ascii_dump(std::ostream&) const) 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;

  //! Swaps \p *this with \p y.
  void swap(Linear_Expression& y);

private:
  /*! \brief
    Holds (between class initialization and finalization) a pointer to
    the (zero-dimension space) constant 0.
  */
  static const Linear_Expression* zero_p;

  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;

  // 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);

  /*! \brief
    Builds the linear expression corresponding to the difference of
    \p v and \p w.

    \exception std::length_error
    Thrown if the space dimension of \p v or the one of \p w exceed
    <CODE>Linear_Expression::max_space_dimension()</CODE>.
  */
  Linear_Expression(Variable v, Variable w);

  friend Linear_Expression
  operator+(const Linear_Expression& e1, const Linear_Expression& e2);
  friend Linear_Expression
  operator+(Coefficient_traits::const_reference n, const Linear_Expression& e);
  friend Linear_Expression
  operator+(const Linear_Expression& e, Coefficient_traits::const_reference n);
  friend Linear_Expression
  operator+(Variable v, const Linear_Expression& e);
  friend Linear_Expression
  operator+(Variable v, Variable w);

  friend Linear_Expression
  operator-(const Linear_Expression& e);

  friend Linear_Expression
  operator-(const Linear_Expression& e1, const Linear_Expression& e2);
  friend Linear_Expression
  operator-(Variable v, Variable w);
  friend Linear_Expression
  operator-(Coefficient_traits::const_reference n, const Linear_Expression& e);
  friend Linear_Expression
  operator-(const Linear_Expression& e, Coefficient_traits::const_reference n);
  friend Linear_Expression
  operator-(Variable v, const Linear_Expression& e);
  friend Linear_Expression
  operator-(const Linear_Expression& e, Variable v);

  friend Linear_Expression
  operator*(Coefficient_traits::const_reference n, const Linear_Expression& e);
  friend Linear_Expression
  operator*(const Linear_Expression& e, Coefficient_traits::const_reference n);

  friend Linear_Expression&
  operator+=(Linear_Expression& e1, const Linear_Expression& e2);
  friend Linear_Expression&
  operator+=(Linear_Expression& e, Variable v);
  friend Linear_Expression&
  operator+=(Linear_Expression& e, Coefficient_traits::const_reference n);

  friend Linear_Expression&
  operator-=(Linear_Expression& e1, const Linear_Expression& e2);
  friend Linear_Expression&
  operator-=(Linear_Expression& e, Variable v);
  friend Linear_Expression&
  operator-=(Linear_Expression& e, Coefficient_traits::const_reference n);

  friend Linear_Expression&
  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);
};

/* 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 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() {
  assert(zero_p != 0);
  return *zero_p;
}

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 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) {
  return Linear_Expression(v, w);
}

/*! \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);
}

inline void
Linear_Expression::ascii_dump(std::ostream& s) const {
  Linear_Row::ascii_dump(s);
}

inline bool
Linear_Expression::ascii_load(std::istream& s) {
  return Linear_Row::ascii_load(s);
}

} // 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 460. */

/* Automatically generated from PPL source file ../src/Constraint.defs.hh line 1. */
/* Constraint 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/Linear_System.types.hh line 1. */


namespace Parma_Polyhedra_Library {

class Linear_System;

} // namespace Parma_Polyhedra_Library

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


namespace Parma_Polyhedra_Library {

class Bit_Row;

} // namespace Parma_Polyhedra_Library

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


namespace Parma_Polyhedra_Library {

class Bit_Matrix;

} // namespace Parma_Polyhedra_Library

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


/* 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/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 // defined(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 // defined(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;
  };

  //! Returns <CODE>true</CODE> if and only if \p *this has no rows.
  /*!
    \note
    The unusual naming for this method is \em intentional:
    we do not want it to be named \c empty because this would cause
    an error prone name clash with the corresponding methods in derived
    classes Constraint_System and Congruence_System (which have a
    different semantics).
  */
  bool has_no_rows() 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$\genfrac{(}{)}{0pt}{}{M}{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(\genfrac{}{}{0pt}{}{M}{0} \genfrac{}{}{0pt}{}{0}{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$\genfrac{(}{)}{0pt}{}{M}{0}\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$\genfrac{(}{)}{0pt}{}{M}{0}\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
    ascii_dump(std::ostream&) const) 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 // defined(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 // defined(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 // defined(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 bool
Matrix::has_no_rows() const {
  return rows.empty();
}

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 366. */

/* 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 // defined(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 // defined(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_Bit_Matrix_iterator;

  /*! \brief
    Sorts the system, removing duplicates, keeping the saturation
    matrix consistent.

    \param sat
    Bit matrix with rows corresponding to the rows of \p *this.
  */
  void sort_and_remove_with_sat(Bit_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 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
    ascii_dump(std::ostream&) const) 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 ascii_dump(std::ostream&) const.  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 // defined(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 // defined(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 // defined(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 Bit_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
  Bit_Row objects.  Access to values is always done on the Row
  objects, but iterator movements and swaps are done on both components.
*/
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
class Parma_Polyhedra_Library::Linear_System::With_Bit_Matrix_iterator {
public:
  typedef std::vector<Row>::iterator Iter1;
  typedef std::vector<Bit_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_Bit_Matrix_iterator(Iter1 iter1, Iter2 iter2);

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

  //! Destructor.
  ~With_Bit_Matrix_iterator();

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

  //! \name Operators Implementing Iterator Movement
  //@{
  With_Bit_Matrix_iterator& operator++();
  With_Bit_Matrix_iterator operator++(int);

  With_Bit_Matrix_iterator& operator--();
  With_Bit_Matrix_iterator operator--(int);

  With_Bit_Matrix_iterator& operator+=(difference_type d);
  With_Bit_Matrix_iterator operator+(difference_type d) const;

  With_Bit_Matrix_iterator& operator-=(difference_type d);
  With_Bit_Matrix_iterator operator-(difference_type d) const;
  //@}

  //! Distance operator.
  difference_type operator-(const With_Bit_Matrix_iterator& y) const;

  //! \name Comparisons between Iterators
  //@{
  bool operator==(const With_Bit_Matrix_iterator& y) const;
  bool operator!=(const With_Bit_Matrix_iterator& y) const;
  bool operator<(const With_Bit_Matrix_iterator& y) const;
  //@}

  //! Dereference operator.
  reference operator*() const;

  //! Access-through operator.
  pointer operator->() const;

  //! Swaps the pointed Row objects while keeping Bit_Matrix consistent.
  void iter_swap(const With_Bit_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_Bit_Matrix_iterator */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
void
iter_swap(Parma_Polyhedra_Library
	  ::Linear_System::With_Bit_Matrix_iterator x,
	  Parma_Polyhedra_Library
	  ::Linear_System::With_Bit_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/Bit_Row.defs.hh line 1. */
/* Bit_Row class declaration.
*/


/* Automatically generated from PPL source file ../src/Bit_Row.defs.hh line 28. */
#include <iosfwd>
#include <gmpxx.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 Bit_Row */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
bool operator==(const Bit_Row& x, const Bit_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 Bit_Row */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
bool operator!=(const Bit_Row& x, const Bit_Row& y);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! The basic comparison function.
/*! \relates Bit_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 // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
int compare(const Bit_Row& x, const Bit_Row& y);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Set-theoretic inclusion test.
/*! \relates Bit_Row */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
bool subset_or_equal(const Bit_Row& x, const Bit_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 Bit_Row
*/
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
bool subset_or_equal(const Bit_Row& x, const Bit_Row& y,
		     bool& strict_subset);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Set-theoretic strict inclusion test.
/*! \relates Bit_Row */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
bool strict_subset(const Bit_Row& x, const Bit_Row& y);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Set-theoretic union.
/*! \relates Bit_Row */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
void set_union(const Bit_Row& x, const Bit_Row& y, Bit_Row& z);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Set-theoretic intersection.
/*! \relates Bit_Row */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
void set_intersection(const Bit_Row& x, const Bit_Row& y, Bit_Row& z);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Set-theoretic difference.
/*! \relates Bit_Row */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
void set_difference(const Bit_Row& x, const Bit_Row& y, Bit_Row& z);

} // namespace Parma_Polyhedra_Library

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! A row in a matrix of bits.
/*! \ingroup PPL_CXX_interface */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
class Parma_Polyhedra_Library::Bit_Row {
public:
  //! Default constructor.
  Bit_Row();

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

  //! Destructor.
  ~Bit_Row();

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

  //! Swaps \p *this with \p y.
  void swap(Bit_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);

  //! Sets bits up to position \p k (excluded).
  void set_until(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 compare(const Bit_Row& x, const Bit_Row& y);
  friend bool operator==(const Bit_Row& x, const Bit_Row& y);
  friend bool operator!=(const Bit_Row& x, const Bit_Row& y);
  friend bool subset_or_equal(const Bit_Row& x, const Bit_Row& y);
  friend bool subset_or_equal(const Bit_Row& x, const Bit_Row& y,
			      bool& strict_subset);
  friend bool strict_subset(const Bit_Row& x, const Bit_Row& y);
  friend void set_union(const Bit_Row& x, const Bit_Row& y, Bit_Row& z);
  friend void set_intersection(const Bit_Row& x, const Bit_Row& y, Bit_Row& z);
  friend void set_difference(const Bit_Row& x, const Bit_Row& y, Bit_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::Bit_Row */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
void swap(Parma_Polyhedra_Library::Bit_Row& x,
	  Parma_Polyhedra_Library::Bit_Row& y);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Specializes <CODE>std::iter_swap</CODE>.
/*! \relates Parma_Polyhedra_Library::Bit_Row */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
void
iter_swap(std::vector<Parma_Polyhedra_Library::Bit_Row>::iterator x,
	  std::vector<Parma_Polyhedra_Library::Bit_Row>::iterator y);

} // namespace std

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


/* Automatically generated from PPL source file ../src/Bit_Row.inlines.hh line 27. */
#include <cassert>

// For the declaration of ffs(3).
#if defined(PPL_HAVE_STRINGS_H)
# include <strings.h>
#elif defined(PPL_HAVE_STRING_H)
# include <string.h>
#endif

namespace Parma_Polyhedra_Library {

inline
Bit_Row::Bit_Row() {
  mpz_init(vec);
}

inline
Bit_Row::Bit_Row(const Bit_Row& y) {
  mpz_init_set(vec, y.vec);
}

inline
Bit_Row::~Bit_Row() {
  mpz_clear(vec);
}

inline Bit_Row&
Bit_Row::operator=(const Bit_Row& y) {
  mpz_set(vec, y.vec);
  return *this;
}

inline void
Bit_Row::set(const unsigned long k) {
  mpz_setbit(vec, k);
}

inline void
Bit_Row::clear(const unsigned long k) {
  mpz_clrbit(vec, k);
}

inline void
Bit_Row::clear_from(const unsigned long k) {
  mpz_tdiv_r_2exp(vec, vec, k);
}

inline unsigned long
Bit_Row::count_ones() const {
  assert(vec->_mp_size >= 0);
  return vec->_mp_size == 0 ? 0 : mpn_popcount(vec->_mp_d, vec->_mp_size);
}

inline bool
Bit_Row::empty() const {
  return mpz_sgn(vec) == 0;
}

inline void
Bit_Row::swap(Bit_Row& y) {
  mpz_swap(vec, y.vec);
}

inline void
Bit_Row::clear() {
  mpz_set_ui(vec, 0UL);
}

inline memory_size_type
Bit_Row::external_memory_in_bytes() const {
  return vec[0]._mp_alloc * PPL_SIZEOF_MP_LIMB_T;
}

inline memory_size_type
Bit_Row::total_memory_in_bytes() const {
  return sizeof(*this) + external_memory_in_bytes();
}

#if PPL_HAVE_DECL_FFS && PPL_SIZEOF_MP_LIMB_T == PPL_SIZEOF_INT

inline unsigned int
Bit_Row::first_one(mp_limb_t w) {
  return ffs(w)-1;
}

#endif

/*! \relates Bit_Row */
inline void
set_union(const Bit_Row& x, const Bit_Row& y, Bit_Row& z) {
  mpz_ior(z.vec, x.vec, y.vec);
}

/*! \relates Bit_Row */
inline void
set_intersection(const Bit_Row& x, const Bit_Row& y, Bit_Row& z) {
  mpz_and(z.vec, x.vec, y.vec);
}

/*! \relates Bit_Row */
inline void
set_difference(const Bit_Row& x, const Bit_Row& y, Bit_Row& z) {
  PPL_DIRTY_TEMP0(mpz_class, complement_y);
  mpz_com(complement_y.get_mpz_t(), y.vec);
  mpz_and(z.vec, x.vec, complement_y.get_mpz_t());
}

} // namespace Parma_Polyhedra_Library


namespace std {

/*! \relates Parma_Polyhedra_Library::Bit_Row */
inline void
swap(Parma_Polyhedra_Library::Bit_Row& x,
     Parma_Polyhedra_Library::Bit_Row& y) {
  x.swap(y);
}

/*! \relates Parma_Polyhedra_Library::Bit_Row */
inline void
iter_swap(std::vector<Parma_Polyhedra_Library::Bit_Row>::iterator x,
	  std::vector<Parma_Polyhedra_Library::Bit_Row>::iterator y) {
  swap(*x, *y);
}

} // namespace std

/* Automatically generated from PPL source file ../src/Bit_Row.defs.hh line 221. */

/* 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 (!has_no_rows())
    set_rows_topology();
}

inline void
Linear_System::set_not_necessarily_closed() {
  row_topology = NOT_NECESSARILY_CLOSED;
  if (!has_no_rows())
    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_Bit_Matrix_iterator::
With_Bit_Matrix_iterator(Iter1 iter1, Iter2 iter2)
  : i1(iter1), i2(iter2) {
}

inline
Linear_System::With_Bit_Matrix_iterator::
With_Bit_Matrix_iterator(const With_Bit_Matrix_iterator& y)
  : i1(y.i1), i2(y.i2) {
}

inline
Linear_System::With_Bit_Matrix_iterator::
~With_Bit_Matrix_iterator() {
}

inline Linear_System::With_Bit_Matrix_iterator&
Linear_System::With_Bit_Matrix_iterator::
operator=(const With_Bit_Matrix_iterator& y) {
  i1 = y.i1;
  i2 = y.i2;
  return *this;
}

inline Linear_System::With_Bit_Matrix_iterator&
Linear_System::With_Bit_Matrix_iterator::operator++() {
  ++i1;
  ++i2;
  return *this;
}

inline Linear_System::With_Bit_Matrix_iterator
Linear_System::With_Bit_Matrix_iterator::operator++(int) {
  With_Bit_Matrix_iterator tmp = *this;
  operator++();
  return tmp;
}

inline Linear_System::With_Bit_Matrix_iterator&
Linear_System::With_Bit_Matrix_iterator::operator--() {
  --i1;
  --i2;
  return *this;
}

inline Linear_System::With_Bit_Matrix_iterator
Linear_System::With_Bit_Matrix_iterator::operator--(int) {
  With_Bit_Matrix_iterator tmp = *this;
  operator--();
  return tmp;
}

inline Linear_System::With_Bit_Matrix_iterator&
Linear_System::With_Bit_Matrix_iterator::operator+=(difference_type d) {
  i1 += d;
  i2 += d;
  return *this;
}

inline Linear_System::With_Bit_Matrix_iterator
Linear_System::With_Bit_Matrix_iterator::
operator+(difference_type d) const {
  With_Bit_Matrix_iterator tmp = *this;
  tmp += d;
  return tmp;
}

inline Linear_System::With_Bit_Matrix_iterator&
Linear_System::With_Bit_Matrix_iterator::operator-=(difference_type d) {
  i1 -= d;
  i2 -= d;
  return *this;
}

inline Linear_System::With_Bit_Matrix_iterator
Linear_System::With_Bit_Matrix_iterator::
operator-(difference_type d) const {
  With_Bit_Matrix_iterator tmp = *this;
  tmp -= d;
  return tmp;
}

inline Linear_System::With_Bit_Matrix_iterator::difference_type
Linear_System::With_Bit_Matrix_iterator::
operator-(const With_Bit_Matrix_iterator& y) const {
  return i1 - y.i1;
}

inline bool
Linear_System::With_Bit_Matrix_iterator::
operator==(const With_Bit_Matrix_iterator& y) const {
  return i1 == y.i1;
}

inline bool
Linear_System::With_Bit_Matrix_iterator::
operator!=(const With_Bit_Matrix_iterator& y) const {
  return i1 != y.i1;
}

inline bool
Linear_System::With_Bit_Matrix_iterator::
operator<(const With_Bit_Matrix_iterator& y) const {
  return i1 < y.i1;
}

inline Linear_System::With_Bit_Matrix_iterator::reference
Linear_System::With_Bit_Matrix_iterator::operator*() const {
  return *i1;
}

inline Linear_System::With_Bit_Matrix_iterator::pointer
Linear_System::With_Bit_Matrix_iterator::operator->() const {
  return &*i1;
}

inline void
Linear_System::With_Bit_Matrix_iterator::
iter_swap(const With_Bit_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_Bit_Matrix_iterator */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
inline void
iter_swap(Parma_Polyhedra_Library
	  ::Linear_System::With_Bit_Matrix_iterator x,
	  Parma_Polyhedra_Library
	  ::Linear_System::With_Bit_Matrix_iterator y) {
  x.iter_swap(y);
}

} // namespace std

/* Automatically generated from PPL source file ../src/Linear_System.defs.hh line 515. */

/* 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);

  //! Builds a system containing copies of any equalities in \p cgs.
  explicit Constraint_System(const Congruence_System& cgs);

  //! 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);

  //! Initializes the class.
  static void initialize();

  //! Finalizes the class.
  static void finalize();

  /*! \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();
  };

  //! Returns <CODE>true</CODE> if and only if \p *this has no constraints.
  bool empty() const;

  /*! \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 // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
  bool OK() const;

  PPL_OUTPUT_DECLARATIONS

  /*! \brief
    Loads from \p s an ASCII representation (as produced by
    ascii_dump(std::ostream&) const) 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;

  //! Swaps \p *this with \p y.
  void swap(Constraint_System& y);

private:
  /*! \brief
    Holds (between class initialization and finalization) a pointer to
    the singleton system containing only Constraint::zero_dim_false().
  */
  static const Constraint_System* zero_dim_empty_p;

  friend class const_iterator;
  friend class Parma_Polyhedra_Library::Polyhedron;

  friend bool 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 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/Constraint.defs.hh line 34. */
#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 v1 = \p v2.
/*! \relates Constraint */
Constraint
operator==(Variable v1, Variable v2);

//! 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 v1 \<= \p v2.
/*! \relates Constraint */
Constraint
operator<=(Variable v1, Variable v2);

//! 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 v1 \>= \p v2.
/*! \relates Constraint */
Constraint
operator>=(Variable v1, Variable v2);

//! 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 v1 \< \p v2.
/*! \relates Constraint */
Constraint
operator<(Variable v1, Variable v2);

//! 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 v1 \> \p v2.
/*! \relates Constraint */
Constraint
operator>(Variable v1, Variable v2);

//! 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 (dimension_type i = c1.space_dimension(); i-- > 0; )
      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);

  //! Copy-constructs from equality congruence \p cg.
  /*!
    \exception std::invalid_argument
    Thrown if \p cg is a proper congruence.
  */
  explicit Constraint(const Congruence& cg);

  //! 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;

  //! Initializes the class.
  static void initialize();

  //! Finalizes the class.
  static void finalize();

  //! 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

  /*! \brief
    Loads from \p s an ASCII representation (as produced by
    ascii_dump(std::ostream&) const) 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;

  //! Swaps \p *this with \p y.
  void swap(Constraint& y);

private:
  /*! \brief
    Holds (between class initialization and finalization) a pointer to
    the unsatisfiable (zero-dimension space) constraint \f$0 = 1\f$.
  */
  static const Constraint* zero_dim_false_p;

  /*! \brief
    Holds (between class initialization and finalization) a pointer to
    the true (zero-dimension space) constraint \f$0 \leq 1\f$, also
    known as <EM>positivity constraint</EM>.
  */
  static const Constraint* zero_dim_positivity_p;

  /*! \brief
    Holds (between class initialization and finalization) a pointer to
    the zero-dimension space constraint \f$\epsilon \geq 0\f$.
  */
  static const Constraint* epsilon_geq_zero_p;

  /*! \brief
    Holds (between class initialization and finalization) a pointer to
    the zero-dimension space constraint \f$\epsilon \leq 1\f$
    (used to implement NNC polyhedra).
  */
  static const Constraint* epsilon_leq_one_p;

  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);

  //! Constructs from a congruence, with specified size and capacity.
  Constraint(const Congruence& cg, dimension_type sz, dimension_type capacity);

  /*! \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* name_var,
			       Variable v) const;

  friend Constraint
  operator==(const Linear_Expression& e1, const Linear_Expression& e2);
  friend Constraint
  operator==(Variable v1, Variable v2);
  friend Constraint
  operator==(const Linear_Expression& e, Coefficient_traits::const_reference n);
  friend Constraint
  operator==(Coefficient_traits::const_reference n, const Linear_Expression& e);

  friend Constraint
  operator>=(const Linear_Expression& e1, const Linear_Expression& e2);
  friend Constraint
  operator>=(Variable v1, Variable v2);
  friend Constraint
  operator>=(const Linear_Expression& e, Coefficient_traits::const_reference n);
  friend Constraint
  operator>=(Coefficient_traits::const_reference n, const Linear_Expression& e);

  friend Constraint
  operator<=(const Linear_Expression& e1, const Linear_Expression& e2);
  friend Constraint
  operator<=(const Linear_Expression& e, Coefficient_traits::const_reference n);
  friend Constraint
  operator<=(Coefficient_traits::const_reference n, const Linear_Expression& e);

  friend Constraint
  operator>(const Linear_Expression& e1, const Linear_Expression& e2);
  friend Constraint
  operator>(Variable v1, Variable v2);
  friend Constraint
  operator>(const Linear_Expression& e, Coefficient_traits::const_reference n);
  friend Constraint
  operator>(Coefficient_traits::const_reference n, const Linear_Expression& e);

  friend Constraint
  operator<(const Linear_Expression& e1, const Linear_Expression& e2);
  friend Constraint
  operator<(const Linear_Expression& e, Coefficient_traits::const_reference n);
  friend Constraint
  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 Variable v1, const Variable v2) {
  Linear_Expression diff
    = (v1.space_dimension() < v2.space_dimension()) ? v1-v2 : v2-v1;
  return Constraint(diff, Constraint::EQUALITY, NECESSARILY_CLOSED);
}

/*! \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 Variable v1, const Variable v2) {
  Linear_Expression diff = v1-v2;
  return Constraint(diff, Constraint::NONSTRICT_INEQUALITY, NECESSARILY_CLOSED);
}

/*! \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>(const Variable v1, const Variable v2) {
  Linear_Expression diff = v1-v2;
  diff -= Variable(std::max(v1.space_dimension(), v2.space_dimension()));
  return Constraint(diff,
                    Constraint::STRICT_INEQUALITY,
                    NOT_NECESSARILY_CLOSED);
}

/*! \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<=(const Variable v1, const Variable v2) {
  return v2 >= v1;
}

/*! \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<(const Variable v1, const Variable v2) {
  return v2 > v1;
}

/*! \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() {
  assert(zero_dim_false_p != 0);
  return *zero_dim_false_p;
}

inline const Constraint&
Constraint::zero_dim_positivity() {
  assert(zero_dim_positivity_p != 0);
  return *zero_dim_positivity_p;
}

inline const Constraint&
Constraint::epsilon_geq_zero() {
  assert(epsilon_geq_zero_p != 0);
  return *epsilon_geq_zero_p;
}

inline const Constraint&
Constraint::epsilon_leq_one() {
  assert(epsilon_leq_one_p != 0);
  return *epsilon_leq_one_p;
}

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 562. */

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


/* 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.types.hh line 1. */


namespace Parma_Polyhedra_Library {

class Poly_Con_Relation;

} // namespace Parma_Polyhedra_Library

/* 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
  operator==(const Poly_Con_Relation& x, const Poly_Con_Relation& y);
  friend bool
  operator!=(const Poly_Con_Relation& x, const Poly_Con_Relation& y);

  friend Poly_Con_Relation
  operator&&(const Poly_Con_Relation& x, const Poly_Con_Relation& y);

  friend Poly_Con_Relation
  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 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 164. */

/* 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 : protected 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);

  //! Initializes the class.
  static void initialize();

  //! Finalizes the class.
  static void finalize();

  /*! \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();
  };

  //! Returns <CODE>true</CODE> if and only if \p *this has no generators.
  bool empty() const;

  /*! \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

  /*! \brief
    Loads from \p s an ASCII representation (as produced by
    ascii_dump(std::ostream&) const) 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.
  */
  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:
  /*! \brief
    Holds (between class initialization and finalization) a pointer to
    the singleton system containing only Generator::zero_dim_point().
  */
  static const Generator_System* zero_dim_univ_p;

  friend class const_iterator;
  friend class Parma_Polyhedra_Library::Polyhedron;
  friend class Parma_Polyhedra_Library::Grid_Generator_System;

  friend bool 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 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/distances.defs.hh line 1. */
/* Class declarations for several distances.
*/


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


namespace Parma_Polyhedra_Library {

template <typename Temp>
struct Rectilinear_Distance_Specialization;

template <typename Temp>
struct Euclidean_Distance_Specialization;

template <typename Temp>
struct L_Infinity_Distance_Specialization;

} // namespace Parma_Polyhedra_Library

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

template <typename Temp>
struct Parma_Polyhedra_Library::Rectilinear_Distance_Specialization {
  static void combine(Temp& running, const Temp& current, Rounding_Dir dir);

  static void finalize(Temp&, Rounding_Dir);
};

template <typename Temp>
struct Parma_Polyhedra_Library::Euclidean_Distance_Specialization {
  static void combine(Temp& running, Temp& current, Rounding_Dir dir);

  static void finalize(Temp& running, Rounding_Dir dir);
};


template <typename Temp>
struct Parma_Polyhedra_Library::L_Infinity_Distance_Specialization {
  static void combine(Temp& running, const Temp& current, Rounding_Dir);

  static void finalize(Temp&, Rounding_Dir);
};

/* Automatically generated from PPL source file ../src/distances.inlines.hh line 1. */
/* Inline functions implementing distances.
*/


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

namespace Parma_Polyhedra_Library {

// A struct to work around the lack of partial specialization
// of function templates in C++.
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 // defined(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);
}

template <typename Temp>
inline void
Rectilinear_Distance_Specialization<Temp>::combine(Temp& running,
						   const Temp& current,
						   Rounding_Dir dir) {
  add_assign_r(running, running, current, dir);
}

template <typename Temp>
inline void
Rectilinear_Distance_Specialization<Temp>::finalize(Temp&, Rounding_Dir) {
}

template <typename Temp>
inline void
Euclidean_Distance_Specialization<Temp>::combine(Temp& running,
						 Temp& current,
						 Rounding_Dir dir) {
  mul_assign_r(current, current, current, dir);
  add_assign_r(running, running, current, dir);
}

template <typename Temp>
inline void
Euclidean_Distance_Specialization<Temp>::finalize(Temp& running,
						  Rounding_Dir dir) {
  sqrt_assign_r(running, running, dir);
}

template <typename Temp>
inline void
L_Infinity_Distance_Specialization<Temp>::combine(Temp& running,
						  const Temp& current,
						  Rounding_Dir) {
  if (current > running)
    running = current;
}

template <typename Temp>
inline void
L_Infinity_Distance_Specialization<Temp>::finalize(Temp&, Rounding_Dir) {
}

} // namespace Parma_Polyhedra_Library

/* Automatically generated from PPL source file ../src/distances.defs.hh line 52. */

/* Automatically generated from PPL source file ../src/Generator.defs.hh line 39. */
#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 (dimension_type i = g1.space_dimension(); i-- > 0; )
      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 // defined(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;

  //! Initializes the class.
  static void initialize();

  //! Finalizes the class.
  static void finalize();

  //! 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

  /*! \brief
    Loads from \p s an ASCII representation (as produced by
    ascii_dump(std::ostream&) const) 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;

  //! Swaps \p *this with \p y.
  void swap(Generator& y);

private:
  /*! \brief
    Holds (between class initialization and finalization) a pointer to
    the origin of the zero-dimensional space \f$\Rset^0\f$.
  */
  static const Generator* zero_dim_point_p;

  /*! \brief
    Holds (between class initialization and finalization) a pointer to
    the origin of the zero-dimensional space \f$\Rset^0\f$, as a closure point.
  */
  static const Generator* zero_dim_closure_point_p;

  /*! \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);

//! Computes the rectilinear (or Manhattan) distance between \p x and \p y.
/*! \relates Generator
  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>.

  \note
  Distances are \e only defined between generators that are points and/or
  closure points; for rays or lines, \c false is returned.
*/
template <typename To>
bool rectilinear_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
                                 const Generator& x,
                                 const Generator& y,
                                 Rounding_Dir dir);

//! Computes the rectilinear (or Manhattan) distance between \p x and \p y.
/*! \relates Generator
  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>.

  \note
  Distances are \e only defined between generators that are points and/or
  closure points; for rays or lines, \c false is returned.
*/
template <typename Temp, typename To>
bool rectilinear_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
                                 const Generator& x,
                                 const Generator& y,
                                 Rounding_Dir dir);

//! Computes the rectilinear (or Manhattan) distance between \p x and \p y.
/*! \relates Generator
  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.

  \note
  Distances are \e only defined between generators that are points and/or
  closure points; for rays or lines, \c false is returned.
*/
template <typename Temp, typename To>
bool rectilinear_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
                                 const Generator& x,
                                 const Generator& y,
                                 Rounding_Dir dir,
                                 Temp& tmp0,
                                 Temp& tmp1,
                                 Temp& tmp2);

//! Computes the euclidean distance between \p x and \p y.
/*! \relates Generator
  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>.

  \note
  Distances are \e only defined between generators that are points and/or
  closure points; for rays or lines, \c false is returned.
*/
template <typename To>
bool euclidean_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
                               const Generator& x,
                               const Generator& y,
                               Rounding_Dir dir);

//! Computes the euclidean distance between \p x and \p y.
/*! \relates Generator
  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>.

  \note
  Distances are \e only defined between generators that are points and/or
  closure points; for rays or lines, \c false is returned.
*/
template <typename Temp, typename To>
bool rectilinear_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
                                 const Generator& x,
                                 const Generator& y,
                                 Rounding_Dir dir);

//! Computes the euclidean distance between \p x and \p y.
/*! \relates Generator
  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.

  \note
  Distances are \e only defined between generators that are points and/or
  closure points; for rays or lines, \c false is returned.
*/
template <typename Temp, typename To>
bool euclidean_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
                               const Generator& x,
                               const Generator& y,
                               Rounding_Dir dir,
                               Temp& tmp0,
                               Temp& tmp1,
                               Temp& tmp2);

//! Computes the \f$L_\infty\f$ distance between \p x and \p y.
/*! \relates Generator
  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>.

  \note
  Distances are \e only defined between generators that are points and/or
  closure points; for rays or lines, \c false is returned.
*/
template <typename To>
bool l_infinity_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
                                const Generator& x,
                                const Generator& y,
                                Rounding_Dir dir);

//! Computes the \f$L_\infty\f$ distance between \p x and \p y.
/*! \relates Generator
  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>.

  \note
  Distances are \e only defined between generators that are points and/or
  closure points; for rays or lines, \c false is returned.
*/
template <typename Temp, typename To>
bool l_infinity_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
                                const Generator& x,
                                const Generator& y,
                                Rounding_Dir dir);

//! Computes the \f$L_\infty\f$ distance between \p x and \p y.
/*! \relates Generator
  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.

  \note
  Distances are \e only defined between generators that are points and/or
  closure points; for rays or lines, \c false is returned.
*/
template <typename Temp, typename To>
bool l_infinity_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
                                const Generator& x,
                                const Generator& y,
                                Rounding_Dir dir,
                                Temp& tmp0,
                                Temp& tmp1,
                                Temp& tmp2);

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() {
  assert(zero_dim_point_p != 0);
  return *zero_dim_point_p;
}

inline const Generator&
Generator::zero_dim_closure_point() {
  assert(zero_dim_closure_point_p != 0);
  return *zero_dim_closure_point_p;
}

/*! \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);
}

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \relates Generator */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename Specialization, typename Temp, typename To>
inline bool
l_m_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
		    const Generator& x,
		    const Generator& y,
		    const Rounding_Dir dir,
		    Temp& tmp0,
		    Temp& tmp1,
		    Temp& tmp2) {
  // Generator kind compatibility check: we only compute distances
  // between (closure) points.
  if (x.is_line_or_ray() || y.is_line_or_ray())
    return false;
  const dimension_type x_space_dim = x.space_dimension();
  // Dimension-compatibility check.
  if (x_space_dim != y.space_dimension())
    return false;

  // All zero-dim generators have distance zero.
  if (x_space_dim == 0) {
    assign_r(r, 0, ROUND_NOT_NEEDED);
    return true;
  }

  PPL_DIRTY_TEMP0(mpq_class, x_coord);
  PPL_DIRTY_TEMP0(mpq_class, y_coord);
  PPL_DIRTY_TEMP0(mpq_class, x_div);
  PPL_DIRTY_TEMP0(mpq_class, y_div);
  assign_r(x_div, x.divisor(), ROUND_NOT_NEEDED);
  assign_r(y_div, y.divisor(), ROUND_NOT_NEEDED);

  assign_r(tmp0, 0, ROUND_NOT_NEEDED);
  for (dimension_type i = x_space_dim; i-- > 0; ) {
    assign_r(x_coord, x.coefficient(Variable(i)), ROUND_NOT_NEEDED);
    div_assign_r(x_coord, x_coord, x_div, ROUND_NOT_NEEDED);
    assign_r(y_coord, y.coefficient(Variable(i)), ROUND_NOT_NEEDED);
    div_assign_r(y_coord, y_coord, y_div, ROUND_NOT_NEEDED);
    const Temp* tmp1p;
    const Temp* tmp2p;

    if (x_coord > y_coord) {
      maybe_assign(tmp1p, tmp1, x_coord, dir);
      maybe_assign(tmp2p, tmp2, y_coord, inverse(dir));
    }
    else {
      maybe_assign(tmp1p, tmp1, y_coord, dir);
      maybe_assign(tmp2p, tmp2, x_coord, inverse(dir));
    }
    sub_assign_r(tmp1, *tmp1p, *tmp2p, dir);
    assert(sgn(tmp1) >= 0);
    Specialization::combine(tmp0, tmp1, dir);
  }
  Specialization::finalize(tmp0, dir);
  assign_r(r, tmp0, dir);
  return true;
}

/*! \relates Generator */
template <typename Temp, typename To>
inline bool
rectilinear_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			    const Generator& x,
			    const Generator& 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);
}

/*! \relates Generator */
template <typename Temp, typename To>
inline bool
rectilinear_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			    const Generator& x,
			    const Generator& y,
			    const Rounding_Dir dir) {
  typedef Checked_Number<Temp, Extended_Number_Policy> Checked_Temp;
  PPL_DIRTY_TEMP(Checked_Temp, tmp0);
  PPL_DIRTY_TEMP(Checked_Temp, tmp1);
  PPL_DIRTY_TEMP(Checked_Temp, tmp2);
  return rectilinear_distance_assign(r, x, y, dir, tmp0, tmp1, tmp2);
}

/*! \relates Generator */
template <typename To>
inline bool
rectilinear_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			    const Generator& x,
			    const Generator& y,
			    const Rounding_Dir dir) {
  return rectilinear_distance_assign<To, To>(r, x, y, dir);
}

/*! \relates Generator */
template <typename Temp, typename To>
inline bool
euclidean_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			  const Generator& x,
			  const Generator& 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);
}

/*! \relates Generator */
template <typename Temp, typename To>
inline bool
euclidean_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			  const Generator& x,
			  const Generator& y,
			  const Rounding_Dir dir) {
  typedef Checked_Number<Temp, Extended_Number_Policy> Checked_Temp;
  PPL_DIRTY_TEMP(Checked_Temp, tmp0);
  PPL_DIRTY_TEMP(Checked_Temp, tmp1);
  PPL_DIRTY_TEMP(Checked_Temp, tmp2);
  return euclidean_distance_assign(r, x, y, dir, tmp0, tmp1, tmp2);
}

/*! \relates Generator */
template <typename To>
inline bool
euclidean_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			  const Generator& x,
			  const Generator& y,
			  const Rounding_Dir dir) {
  return euclidean_distance_assign<To, To>(r, x, y, dir);
}

/*! \relates Generator */
template <typename Temp, typename To>
inline bool
l_infinity_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			   const Generator& x,
			   const Generator& 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);
}

/*! \relates Generator */
template <typename Temp, typename To>
inline bool
l_infinity_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			   const Generator& x,
			   const Generator& y,
			   const Rounding_Dir dir) {
  typedef Checked_Number<Temp, Extended_Number_Policy> Checked_Temp;
  PPL_DIRTY_TEMP(Checked_Temp, tmp0);
  PPL_DIRTY_TEMP(Checked_Temp, tmp1);
  PPL_DIRTY_TEMP(Checked_Temp, tmp2);
  return l_infinity_distance_assign(r, x, y, dir, tmp0, tmp1, tmp2);
}

/*! \relates Generator */
template <typename To>
inline bool
l_infinity_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			   const Generator& x,
			   const Generator& y,
			   const Rounding_Dir dir) {
  return l_infinity_distance_assign<To, To>(r, x, y, dir);
}

} // 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 722. */

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


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


/* 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/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

} // 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 relational constraint.
  */
  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);

  //! Initializes the class.
  static void initialize();

  //! Finalizes the class.
  static void finalize();

  //! 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();
  };

  //! Returns <CODE>true</CODE> if and only if \p *this has no congruences.
  bool empty() const;

  /*! \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 // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
  bool OK() const;

  PPL_OUTPUT_DECLARATIONS

  /*! \brief
    Loads from \p s an ASCII representation (as produced by
    ascii_dump(std::ostream&) const) 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;

  //! 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(\genfrac{}{}{0pt}{}{0}{A} \genfrac{}{}{0pt}{}{B}{A}\bigr)\f$
    where \f$B\f$ is the \f$dims \times dims\f$ unit matrix of the form
    \f$\bigl(\genfrac{}{}{0pt}{}{0}{1} \genfrac{}{}{0pt}{}{1}{0}\bigr)\f$.
    The matrix is expanded avoiding reallocation whenever possible.
  */
  void add_unit_rows_and_columns(dimension_type dims);

protected:

  //! Returns <CODE>true</CODE> if \p g satisfies all the congruences.
  bool satisfies_all_congruences(const Grid_Generator& g) const;

private:
  /*! \brief
    Holds (between class initialization and finalization) a pointer to
    the singleton system containing only Congruence::zero_dim_false().
  */
  static const Congruence_System* zero_dim_empty_p;

  //! Builds an empty (i.e. zero rows) system of dimension \p d.
  explicit Congruence_System(dimension_type d);

  /*! \brief
    Concatenates copies of the congruences from \p cgs onto \p *this.

    \param cgs
    The congruence system to append to \p this.  The number of rows in
    \p cgs must be strictly positive.

    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);

  //! 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(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;
  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
  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);

  /*! \brief
    Removes the higher dimensions of the system so that the resulting
    system will have dimension \p new_dimension.

    The value of \p new_dimension must be at most the space dimension
    of \p *this.
  */
  void remove_higher_space_dimensions(dimension_type new_dimension);

  //! Resizes the system without worrying about the old contents.
  /*!
    \param new_num_rows
    The number of rows of the resized system;

    \param new_num_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_num_rows,
		      dimension_type new_num_columns);
};

// Congruence_System.inlines.hh is not included here on purpose.

/* Automatically generated from PPL source file ../src/Congruence.defs.hh line 36. */
#include <iosfwd>

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, 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, Coefficient_traits::const_reference k);

//! Creates a congruence from \p c, with \p m as the modulus.
/*! \relates Congruence */
Congruence
operator/(const Constraint& c, 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;
  const Coefficient& m = cg1.modulus();
  if (m == 0)
    cout << "Congruence cg1 is an equality." << endl;
  else {
    Linear_Expression e;
    for (dimension_type i = cg1.space_dimension(); i-- > 0; )
      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 an inequality.
  */
  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/=(Coefficient_traits::const_reference k);

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this is a tautology
    (i.e., an always true congruence).

    A tautological congruence has 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 \f$b = 0 \pmod{m}\f$.
  */
  bool is_tautological() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if
    \p *this is inconsistent (i.e., an always false congruence).

    An inconsistent congruence has 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 proper congruence: \f$\sum_{i=0}^{n-1} 0 x_i + b \%= 0 / m\f$,
      where \f$b \neq 0 \pmod{m}\f$.
  */
  bool is_inconsistent() 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;

  //! Initializes the class.
  static void initialize();

  //! Finalizes the class.
  static void finalize();

  /*! \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();

  //! Returns the congruence \f$e1 = e2 \pmod{1}\f$.
  static Congruence
  create(const Linear_Expression& e1, const Linear_Expression& e2);

  //! Returns the congruence \f$e = n \pmod{1}\f$.
  static Congruence
  create(const Linear_Expression& e, Coefficient_traits::const_reference n);

  //! Returns the congruence \f$n = e \pmod{1}\f$.
  static Congruence
  create(Coefficient_traits::const_reference n, const Linear_Expression& e);

  /*! \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

  /*! \brief
    Loads from \p s an ASCII representation of the internal
    representation of \p *this.
  */
  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:
  /*! \brief
    Holds (between class initialization and finalization) a pointer to
    the false (zero-dimension space) congruence \f$0 = 1 \pmod{0}\f$.
  */
  static const Congruence* zero_dim_false_p;

  /*! \brief
    Holds (between class initialization and finalization) a pointer 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_p;

  //! 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, which must be zero or greater.
  */
  Congruence(Linear_Expression& le,
	     Coefficient_traits::const_reference m);

  //! 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
  operator/(const Congruence& cg, Coefficient_traits::const_reference k);
  friend Congruence
  operator/(const Constraint& c, Coefficient_traits::const_reference m);

  friend bool
  operator==(const Congruence& x, const Congruence& y);

  friend bool
  operator!=(const Congruence& x, const Congruence& y);

  friend std::ostream&
  Parma_Polyhedra_Library::IO_Operators
  ::operator<<(std::ostream& s,
	       const Congruence_System& cgs);

  friend class Parma_Polyhedra_Library::Scalar_Products;
  friend class Parma_Polyhedra_Library::Constraint;
  friend class Parma_Polyhedra_Library::Congruence_System;
  friend class Parma_Polyhedra_Library::Congruence_System::const_iterator;
  // FIXME: The following friend declaration is at least for
  //        operator[] access in Grid::conversion.
  friend class Parma_Polyhedra_Library::Grid;
  friend class Parma_Polyhedra_Library::Linear_Expression;

  friend void
  std::swap(Parma_Polyhedra_Library::Congruence& x,
	    Parma_Polyhedra_Library::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
Congruence::Congruence(Linear_Expression& le,
		       Coefficient_traits::const_reference m) {
  Row::swap(static_cast<Row&>(le));
  assert(m >= 0);
  (*this)[size()-1] = m;
}

inline Congruence
Congruence::create(const Linear_Expression& e,
		   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);
  return cg;
}

inline Congruence
Congruence::create(Coefficient_traits::const_reference n,
		   const Linear_Expression& e) {
  // Ensure that diff has capacity for the modulus.
  Linear_Expression diff(e, e.space_dimension() + 2);
  diff -= n;
  Congruence cg(diff, 1);
  return cg;
}

/*! \relates Parma_Polyhedra_Library::Congruence */
inline Congruence
operator%=(const Linear_Expression& e1, const Linear_Expression& e2) {
  return Congruence::create(e1, e2);
}

/*! \relates Parma_Polyhedra_Library::Congruence */
inline Congruence
operator%=(const Linear_Expression& e, Coefficient_traits::const_reference n) {
  return Congruence::create(e, n);
}

/*! \relates Parma_Polyhedra_Library::Congruence */
inline Congruence
operator/(const Congruence& cg, Coefficient_traits::const_reference k) {
  Congruence ret(cg, k);
  return ret;
}

inline const Congruence&
Congruence::zero_dim_integrality() {
  return *zero_dim_integrality_p;
}

inline const Congruence&
Congruence::zero_dim_false() {
  return *zero_dim_false_p;
}

inline Congruence&
Congruence::operator=(const Congruence& c) {
  Row::operator=(c);
  return *this;
}

/*! \relates Congruence */
inline Congruence
operator/(const Constraint& c, Coefficient_traits::const_reference m) {
  Congruence ret(c);
  return ret / m;
}

inline Congruence&
Congruence::operator/=(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() > 1);
  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() {
  (*this)[size()-1] = 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 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 478. */

/* 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_System.defs.hh line 1. */
/* Grid_Generator_System class declaration.
*/


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


namespace Parma_Polyhedra_Library {

class Variables_Set;

} // namespace Parma_Polyhedra_Library

/* 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:
  //! Default constructor: builds an empty system of generators.
  Grid_Generator_System();

  //! Builds the singleton system containing only generator \p g.
  explicit Grid_Generator_System(const Grid_Generator& g);

  //! Builds an empty system of generators of dimension \p dim.
  explicit Grid_Generator_System(dimension_type dim);

  //! Ordinary copy-constructor.
  Grid_Generator_System(const Grid_Generator_System& gs);

  //! Destructor.
  ~Grid_Generator_System();

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

  //! 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);

  //! Initializes the class.
  static void initialize();

  //! Finalizes the class.
  static void finalize();

  /*! \brief
    Returns the singleton system containing only
    Grid_Generator::zero_dim_point().
  */
  static const Grid_Generator_System& zero_dim_univ();

  //! 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);
  };

  //! Returns <CODE>true</CODE> if and only if \p *this has no generators.
  bool empty() const;

  /*! \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;

  //! Returns the number of rows (generators) in the system.
  dimension_type num_rows() 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;

  //! 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;

  PPL_OUTPUT_DECLARATIONS

  /*! \brief
    Loads from \p s an ASCII representation (as produced by
    ascii_dump(std::ostream&) const) 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.
  */
  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(Grid_Generator_System& y);

private:
  /*! \brief
    Holds (between class initialization and finalization) a pointer to
    the singleton system containing only Grid_Generator::zero_dim_point().
  */
  static const Grid_Generator_System* zero_dim_univ_p;

  friend class Grid;

  friend bool
  operator==(const Grid_Generator_System& x, const Grid_Generator_System& y);

  //! 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);

  //! 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;

  //! 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);

  /*! \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(\genfrac{}{}{0pt}{}{A}{0} \genfrac{}{}{0pt}{}{0}{B}\bigr)\f$
    where \f$B\f$ is the \f$dims \times dims\f$ unit matrix of the form
    \f$\bigl(\genfrac{}{}{0pt}{}{1}{0} \genfrac{}{}{0pt}{}{0}{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.
  /*!
    The space dimension of the variable with the highest space
    dimension in \p to_be_removed must be at most 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.

    The value of \p new_dimension must be at most the space dimension
    of \p *this.
  */
  void remove_higher_space_dimensions(dimension_type new_dimension);

  //! Resizes the system without worrying about the old contents.
  /*!
    \param new_num_rows
    The number of rows of the resized system;

    \param new_num_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_num_rows,
		      dimension_type new_num_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/Grid_Generator.defs.hh line 31. */
#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 grid line, parameter or grid point.
/*! \ingroup PPL_CXX_interface
  An object of the class Grid_Generator is one of the following:

  - a grid_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 grid_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 grid_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>grid_line</CODE>, <CODE>parameter</CODE>
  or <CODE>grid_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 grid 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 grid 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 grid 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 grid 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 grid 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 grid 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 grid 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 grid 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 << "Grid point g1: " << g1 << endl;
    Linear_Expression e;
    for (dimension_type i = g1.space_dimension(); i-- > 0; )
      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 grid point." << endl;
  \endcode
  Therefore, for the grid point
  \code
  Grid_Generator g1 = grid_point(2*x - y + 3*z, 2);
  \endcode
  we would obtain the following output:
  \code
  Grid point g1: p((2*A - B + 3*C)/2)
  Parameter g2: parameter((2*A - 2*B + 9*C)/2)
  \endcode
  When working with grid 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:
  //! 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 grid_line(const Linear_Expression& e);

  //! Returns the parameter of direction \p e and size \p e/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 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 grid_point(const Linear_Expression& e
				   = Linear_Expression::zero(),
				   Coefficient_traits::const_reference d
				   = Coefficient_one());

  //! Ordinary copy-constructor.
  Grid_Generator(const Grid_Generator& g);

  //! Destructor.
  ~Grid_Generator();

  //! Assignment operator.
  Grid_Generator& operator=(const Grid_Generator& g);

  //! Assignment operator.
  Grid_Generator& operator=(const Generator& g);

  //! Returns the maximum space dimension a Grid_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 grid line. */
    LINE,
    /*! The generator is a parameter. */
    PARAMETER,
    /*! The generator is a grid 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 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 divisor of \p *this.
  /*!
    \exception std::invalid_argument
    Thrown if \p *this is a line.
  */
  Coefficient_traits::const_reference divisor() const;

  //! Initializes the class.
  static void initialize();

  //! Finalizes the class.
  static void finalize();

  //! Returns the origin of the zero-dimensional space \f$\Rset^0\f$.
  static const Grid_Generator& zero_dim_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 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 \p *this is equal to \p gg in
    dimension \p dim.
  */
  bool is_equal_at_dimension(dimension_type dim,
			     const Grid_Generator& gg) 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;

  PPL_OUTPUT_DECLARATIONS

  /*! \brief
    Loads from \p s an ASCII representation (as produced by
    ascii_dump(std::ostream&) const) 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;

  //! 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 elements 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);

private:
  /*! \brief
    Holds (between class initialization and finalization) a pointer to
    the origin of the zero-dimensional space \f$\Rset^0\f$.
  */
  static const Grid_Generator* zero_dim_point_p;

  /*! \brief
    Scales \p *this to be represented with a divisor of \p d (if
    \*this is a parameter or point).

    It is assumed that \p d is a multiple of the current divisor.

    \exception std::invalid_argument
    Thrown if \p d is zero.
  */
  void scale_to_divisor(Coefficient_traits::const_reference d);

  /*! \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);

  //! Sets the divisor of \p *this to \p d.
  /*!
    \exception std::invalid_argument
    Thrown if \p *this is a line.
  */
  void set_divisor(Coefficient_traits::const_reference d);

  //! 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();

  //! Converts the Grid_Generator into a parameter.
  void set_is_parameter();

  /*! \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, Grid::simplify,
  //        Grid::relation_with(c) and Grid::Grid(box, *).
  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;
  friend class Linear_Expression;
};


namespace Parma_Polyhedra_Library {

/*! \brief
  Shorthand for Grid_Generator
  Grid_Generator::grid_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::grid_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.inlines.hh line 1. */
/* Grid Generator class implementation: inline functions.
*/


namespace Parma_Polyhedra_Library {

inline
Grid_Generator::Grid_Generator(const Grid_Generator& g)
  : Generator(g) {
}

inline
Grid_Generator::~Grid_Generator() {
}

inline
Grid_Generator::Grid_Generator(Generator g)
  : Generator(Generator::point()) {
  Generator::swap(g);
}

inline dimension_type
Grid_Generator::size() const {
  return Generator::size();
}

inline dimension_type
Grid_Generator::max_space_dimension() {
  return Generator::max_space_dimension() - 1;
}

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);
}

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_divisor(Coefficient_traits::const_reference d) {
  assert(!is_line());
  if (is_line_or_parameter())
    Generator::operator[](size() - 1) = d;
  else
    Generator::operator[](0) = d;
}

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);
  else
    return Generator::operator[](0);
}

inline bool
Grid_Generator::is_equal_at_dimension(dimension_type dim,
				      const Grid_Generator& gg) const {
  return operator[](dim) * gg.divisor() == gg[dim] * divisor();
}

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_traits::const_reference
Grid_Generator::coefficient(const Variable v) const {
  if (v.space_dimension() > space_dimension())
    throw_dimension_incompatible("coefficient(v)", "v", v);
  return Generator::coefficient(v);
}

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 const Grid_Generator&
Grid_Generator::zero_dim_point() {
  assert(zero_dim_point_p != 0);
  return *zero_dim_point_p;
}

inline void
Grid_Generator::strong_normalize() {
  Generator::strong_normalize();
}

inline void
Grid_Generator::swap(Grid_Generator& y) {
  Generator::swap(y);
}

/*! \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::grid_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::grid_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/Grid_Generator.defs.hh line 534. */

/* 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) {
  PPL_DIRTY_TEMP_COEFFICIENT(z);
  assign(z, x, y);
  return sgn(z);
}

inline int
Scalar_Products::reduced_sign(const Linear_Row& x, const Linear_Row& y) {
  PPL_DIRTY_TEMP_COEFFICIENT(z);
  reduced_assign(z, x, y);
  return sgn(z);
}

inline int
Scalar_Products::homogeneous_sign(const Linear_Row& x, const Linear_Row& y) {
  PPL_DIRTY_TEMP_COEFFICIENT(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::sign(const Constraint& c, const Grid_Generator& g) {
  PPL_DIRTY_TEMP_COEFFICIENT(z);
  assign(z, c, g);
  return sgn(z);
}

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 int
Scalar_Products::homogeneous_sign(const Grid_Generator& g,
				  const Constraint& c) {
  PPL_DIRTY_TEMP_COEFFICIENT(z);
  homogeneous_assign(z, g, c);
  return sgn(z);
}

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 196. */

/* 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.types.hh line 1. */


namespace Parma_Polyhedra_Library {

class BHRZ03_Certificate;

} // namespace Parma_Polyhedra_Library

/* 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 // defined(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 // defined(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.types.hh line 1. */


namespace Parma_Polyhedra_Library {

class H79_Certificate;

} // namespace Parma_Polyhedra_Library

/* 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/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() {
  assert(zero_dim_empty_p != 0);
  return *zero_dim_empty_p;
}

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 bool
Constraint_System::empty() const {
  return begin() == end();
}

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_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 bool
Generator_System::empty() const {
  return Linear_System::has_no_rows();
}

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() {
  assert(zero_dim_univ_p != 0);
  return *zero_dim_univ_p;
}

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/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&
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 void
Congruence_System::insert(const Congruence& cg) {
  insert_verbatim(cg);
  static_cast<Congruence&>(operator[](rows.size()-1)).strong_normalize();
  assert(OK());
}

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(const dimension_type d)
  : Matrix(0, d + 2) {
}

inline
Congruence_System::~Congruence_System() {
}

inline Congruence_System&
Congruence_System::operator=(const Congruence_System& y) {
  Matrix::operator=(y);
  return *this;
}

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::resize_no_copy(const dimension_type new_num_rows,
				  const dimension_type new_num_columns) {
  Matrix::resize_no_copy(new_num_rows, new_num_columns, Row::Flags());
}

inline const Congruence_System&
Congruence_System::zero_dim_empty() {
  assert(zero_dim_empty_p != 0);
  return *zero_dim_empty_p;
}

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 bool
Congruence_System::empty() const {
  return begin() == end();
}

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/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 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_num_rows,
				      const dimension_type new_num_columns) {
  Generator_System::resize_no_copy(new_num_rows, new_num_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));
}

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
Grid_Generator_System::~Grid_Generator_System() {
}

inline Grid_Generator_System&
Grid_Generator_System::operator=(const Grid_Generator_System& y) {
  Generator_System::operator=(y);
  return *this;
}

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 const Grid_Generator_System&
Grid_Generator_System::zero_dim_univ() {
  assert(zero_dim_univ_p != 0);
  return *zero_dim_univ_p;
}

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_rows() 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 bool
Grid_Generator_System::empty() const {
  return Generator_System::empty();
}

inline
Grid_Generator_System
::const_iterator::const_iterator(const Generator_System::const_iterator& y)
  : Generator_System::const_iterator::const_iterator(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 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));
}

/*! \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/Bit_Matrix.defs.hh line 1. */
/* Bit_Matrix class declaration.
*/


/* Automatically generated from PPL source file ../src/Bit_Matrix.defs.hh line 29. */
#include <vector>
#include <iosfwd>

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! A matrix of bits.
/*! \ingroup PPL_CXX_interface */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
class Parma_Polyhedra_Library::Bit_Matrix {
public:
  //! Default constructor.
  Bit_Matrix();

  //! Construct a bit matrix with \p n_rows rows and \p n_columns columns.
  Bit_Matrix(dimension_type n_rows, dimension_type n_columns);

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

  //! Destructor.
  ~Bit_Matrix();

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

  //! Swaps \p *this with \p y.
  void swap(Bit_Matrix& y);

  //! Subscript operator.
  Bit_Row& operator[](dimension_type k);

  //! Constant subscript operator.
  const Bit_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 Bit_Matrix& y);

  //! Returns the maximum number of rows of a Bit_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 bit matrix (this ensures better efficiency),
    tells whether it contains the given row.
  */
  bool sorted_contains(const Bit_Row& row) const;

  //! Adds \p row to \p *this.
  void add_row(const Bit_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
    ascii_dump(std::ostream&) const) 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<Bit_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 Bit_Row_Less_Than {
    bool operator()(const Bit_Row& x, const Bit_Row& y) const;
  };

  friend
  void Parma_Polyhedra_Library::
  Linear_System::sort_and_remove_with_sat(Bit_Matrix& sat);

};

namespace Parma_Polyhedra_Library {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Returns <CODE>true</CODE> if and only if \p x and \p y are equal.
/*! \relates Bit_Matrix */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
bool operator==(const Bit_Matrix& x, const Bit_Matrix& y);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Returns <CODE>true</CODE> if and only if \p x and \p y are not equal.
/*! \relates Bit_Matrix */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
bool operator!=(const Bit_Matrix& x, const Bit_Matrix& y);

} // namespace Parma_Polyhedra_Library

namespace std {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Specializes <CODE>std::swap</CODE>.
/*! \relates Parma_Polyhedra_Library::Bit_Matrix */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
void swap(Parma_Polyhedra_Library::Bit_Matrix& x,
	  Parma_Polyhedra_Library::Bit_Matrix& y);

} // namespace std

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


#include <algorithm>
#include <cassert>

namespace Parma_Polyhedra_Library {

inline
Bit_Matrix::Bit_Matrix()
  : rows(),
    row_size(0) {
}

inline dimension_type
Bit_Matrix::max_num_rows() {
  return std::vector<Bit_Row>().max_size();
}

inline
Bit_Matrix::Bit_Matrix(const dimension_type n_rows,
		       const dimension_type n_columns)
  : rows(n_rows),
    row_size(n_columns) {
}

inline
Bit_Matrix::Bit_Matrix(const Bit_Matrix& y)
  : rows(y.rows),
    row_size(y.row_size) {
}

inline
Bit_Matrix::~Bit_Matrix() {
}

inline void
Bit_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
Bit_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
Bit_Matrix::swap(Bit_Matrix& y) {
  std::swap(row_size, y.row_size);
  std::swap(rows, y.rows);
}

inline Bit_Row&
Bit_Matrix::operator[](const dimension_type k) {
  assert(k < rows.size());
  return rows[k];
}

inline const Bit_Row&
Bit_Matrix::operator[](const dimension_type k) const {
  assert(k < rows.size());
  return rows[k];
}

inline dimension_type
Bit_Matrix::num_columns() const {
  return row_size;
}

inline dimension_type
Bit_Matrix::num_rows() const {
  return rows.size();
}

inline void
Bit_Matrix::clear() {
  // Clear `rows' and minimize its capacity.
  std::vector<Bit_Row>().swap(rows);
  row_size = 0;
}

inline memory_size_type
Bit_Matrix::total_memory_in_bytes() const {
  return sizeof(*this) + external_memory_in_bytes();
}

inline bool
Bit_Matrix::Bit_Row_Less_Than::
operator()(const Bit_Row& x, const Bit_Row& y) const {
  return compare(x, y) < 0;
}

inline bool
Bit_Matrix::sorted_contains(const Bit_Row& row) const {
  assert(check_sorted());
  return std::binary_search(rows.begin(), rows.end(), row,
			    Bit_Row_Less_Than());
}

/*! \relates Bit_Matrix */
inline bool
operator!=(const Bit_Matrix& x, const Bit_Matrix& y) {
  return !(x == y);
}

} // namespace Parma_Polyhedra_Library


namespace std {

/*! \relates Parma_Polyhedra_Library::Bit_Matrix */
inline void
swap(Parma_Polyhedra_Library::Bit_Matrix& x,
     Parma_Polyhedra_Library::Bit_Matrix& y) {
  x.swap(y);
}

} // namespace std

/* Automatically generated from PPL source file ../src/Bit_Matrix.defs.hh line 178. */

/* 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.types.hh line 1. */


namespace Parma_Polyhedra_Library {

class Poly_Gen_Relation;

} // namespace Parma_Polyhedra_Library

/* 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
  operator==(const Poly_Gen_Relation& x, const Poly_Gen_Relation& y);
  friend bool
  operator!=(const Poly_Gen_Relation& x, const Poly_Gen_Relation& y);

  friend Poly_Gen_Relation
  operator&&(const Poly_Gen_Relation& x, const Poly_Gen_Relation& y);

  friend Poly_Gen_Relation
  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 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 137. */

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


namespace Parma_Polyhedra_Library {

template <typename Interval>
class Box;

} // 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/Octagonal_Shape.types.hh line 1. */


namespace Parma_Polyhedra_Library {

template <typename T>
class Octagonal_Shape;

}

/* Automatically generated from PPL source file ../src/Polyhedron.defs.hh line 50. */
#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 Interfaces {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \brief
  Returns \c true if and only if
  <code>ph.topology() == NECESSARILY_CLOSED</code>.
*/
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
bool is_necessarily_closed_for_interfaces(const Polyhedron& ph);

} // namespace Interfaces

} // 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.

  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:
  //! The numeric type of coefficients.
  typedef Coefficient coefficient_type;

  //! Returns the maximum space dimension all kinds of Polyhedron can handle.
  static dimension_type max_space_dimension();

  /*! \brief
    Returns \c true indicating that this domain has methods that
    can recycle constraints.
  */
  static bool can_recycle_constraint_systems();

  //! Initializes the class.
  static void initialize();

  //! Finalizes the class.
  static void finalize();

  /*! \brief
    Returns \c false indicating that this domain cannot recycle congruences.
  */
  static bool can_recycle_congruence_systems();

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.
  /*!
    The complexity argument is ignored.
  */
  Polyhedron(const Polyhedron& y,
             Complexity_Class complexity = ANY_COMPLEXITY);

  //! 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 may be
    recycled to build the polyhedron.

    \param dummy
    A dummy tag to syntactically differentiate this one
    from the other constructors.

    \exception std::invalid_argument
    Thrown if the topology of \p cs is incompatible with \p topol.
  */
  Polyhedron(Topology topol, Constraint_System& cs, Recycle_Input dummy);

  //! 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 may be
    recycled to build the polyhedron.

    \param dummy
    A dummy tag to syntactically differentiate this one
    from the other constructors.

    \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, Recycle_Input dummy);

  //! Builds a polyhedron from a box.
  /*!
    This will use an algorithm whose complexity is polynomial and build
    the smallest polyhedron with topology \p topol containing \p box.

    \param topol
    The topology of the polyhedron;

    \param box
    The box representing the polyhedron to be built;

    \param complexity
    This argument is ignored.
  */
  template <typename Interval>
  Polyhedron(Topology topol, const Box<Interval>& box,
             Complexity_Class complexity = ANY_COMPLEXITY);

  /*! \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;

  //! Returns a system of (equality) congruences satisfied by \p *this.
  Congruence_System congruences() const;

  /*! \brief
    Returns a system of (equality) congruences satisfied by \p *this,
    with no redundant congruences and having the same affine dimension
    as \p *this.
  */
  Congruence_System minimized_congruences() const;

  //! Returns a universe system of grid generators.
  Grid_Generator_System grid_generators() const;

  //! Returns a universe system of grid generators.
  Grid_Generator_System minimized_grid_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 the relations holding between the polyhedron \p *this
    and the congruence \p c.

    \exception std::invalid_argument
    Thrown if \p *this and congruence \p c are dimension-incompatible.
  */
  Poly_Con_Relation relation_with(const Congruence& cg) 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;

  //! Returns <CODE>true</CODE> if and only if \p *this is discrete.
  bool is_discrete() 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 *this
    contains at least one integer point.
  */
  bool contains_integer_point() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p var is constrained in
    \p *this.

    \exception std::invalid_argument
    Thrown if \p var is not a space dimension of \p *this.
  */
  bool constrains(Variable var) 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 g
    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 g are left untouched.
  */
  bool maximize(const Linear_Expression& expr,
		Coefficient& sup_n, Coefficient& sup_d, bool& maximum,
		Generator& g) 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 g
    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 g are left untouched.
  */
  bool minimize(const Linear_Expression& expr,
		Coefficient& inf_n, Coefficient& inf_d, bool& minimum,
		Generator& g) 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;

  //! 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).

    \param c
    The constraint that will be added to the system of
    constraints of \p *this.

    \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

    \param c
    The constraint that will be added to the system of
    constraints of \p *this.

    \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.

    \deprecated
    See \ref A_Note_on_the_Implementation_of_the_Operators.
  */
  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.

    \deprecated
    See \ref A_Note_on_the_Implementation_of_the_Operators.
  */
  bool add_generator_and_minimize(const Generator& g);

  /*! \brief
    Adds a copy of congruence \p cg to \p *this,
    if \p cg can be exactly represented by a polyhedron.

    \exception std::invalid_argument
    Thrown if \p *this and congruence \p cg are dimension-incompatible,
    of if \p cg is a proper congruence which is neither a tautology,
    nor a contradiction.
  */
  void add_congruence(const Congruence& cg);

  /*! \brief
    Adds a copy of congruence \p cg to \p *this,
    if \p cg can be exactly represented by a polyhedron,
    minimizing 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,
    of if \p cg is a proper congruence which is neither a tautology,
    nor a contradiction.

    \deprecated
    See \ref A_Note_on_the_Implementation_of_the_Operators.
  */
  bool add_congruence_and_minimize(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 to be added to \p *this.  The constraints in
    \p cs may be recycled.

    \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.

    \deprecated
    See \ref A_Note_on_the_Implementation_of_the_Operators.
  */
  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 to be added to \p *this.  The constraints in
    \p cs may be recycled.

    \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.

    \deprecated
    See \ref A_Note_on_the_Implementation_of_the_Operators.
  */
  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 to be added to \p *this.  The generators in
    \p gs may be recycled.

    \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.

    \deprecated
    See \ref A_Note_on_the_Implementation_of_the_Operators.
  */
  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 to be added to \p *this.  The generators in
    \p gs may be recycled.

    \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.

    \deprecated
    See \ref A_Note_on_the_Implementation_of_the_Operators.
  */
  bool add_recycled_generators_and_minimize(Generator_System& gs);

  /*! \brief
    Adds a copy of the congruences in \p cgs to \p *this,
    if all the congruences can be exactly represented by a polyhedron.

    \param cgs
    The congruences to be added.

    \exception std::invalid_argument
    Thrown if \p *this and \p cgs are dimension-incompatible,
    of if there exists in \p cgs a proper congruence which is
    neither a tautology, nor a contradiction.
  */
  void add_congruences(const Congruence_System& cgs);

  /*! \brief
    Adds a copy of the congruences in \p cgs to \p *this,
    if all the congruences can be exactly represented by a polyhedron,
    minimizing the result.

    \return
    <CODE>false</CODE> if and only if the result is empty.

    \param cgs
    The congruences to be added.

    \exception std::invalid_argument
    Thrown if \p *this and \p cgs are dimension-incompatible,
    of if there exists in \p cgs a proper congruence which is
    neither a tautology, nor a contradiction

    \deprecated
    See \ref A_Note_on_the_Implementation_of_the_Operators.
  */
  bool add_congruences_and_minimize(const Congruence_System& cgs);

  /*! \brief
    Adds the congruences in \p cgs to \p *this,
    if all the congruences can be exactly represented by a polyhedron.

    \param cgs
    The congruences to be added. Its elements may be recycled.

    \exception std::invalid_argument
    Thrown if \p *this and \p cgs are dimension-incompatible,
    of if there exists in \p cgs a proper congruence which is
    neither a tautology, nor a contradiction

    \warning
    The only assumption that can be made on \p cgs upon successful or
    exceptional return is that it can be safely destroyed.
  */
  void add_recycled_congruences(Congruence_System& cgs);

  /*! \brief
    Adds the congruences in \p cgs to \p *this,
    if all the congruences can be exactly represented by a polyhedron,
    minimizing the result.

    \return
    <CODE>false</CODE> if and only if the result is empty.

    \param cgs
    The congruences to be added. Its elements may be recycled.

    \exception std::invalid_argument
    Thrown if \p *this and \p cgs are dimension-incompatible,
    of if there exists in \p cgs a proper congruence which is
    neither a tautology, nor a contradiction

    \warning
    The only assumption that can be made on \p cgs upon successful or
    exceptional return is that it can be safely destroyed.

    \deprecated
    See \ref A_Note_on_the_Implementation_of_the_Operators.
  */
  bool add_recycled_congruences_and_minimize(Congruence_System& cgs);

  /*! \brief
    Uses a copy of constraint \p c to refine \p *this.

    \exception std::invalid_argument
    Thrown if \p *this and constraint \p c are dimension-incompatible.
  */
  void refine_with_constraint(const Constraint& c);

  /*! \brief
    Uses a copy of congruence \p cg to refine \p *this.

    \exception std::invalid_argument
    Thrown if \p *this and congruence \p cg are dimension-incompatible.
  */
  void refine_with_congruence(const Congruence& cg);

  /*! \brief
    Uses a copy of the constraints in \p cs to refine \p *this.

    \param cs
    Contains the constraints used to refine the system of
    constraints of \p *this.

    \exception std::invalid_argument
    Thrown if \p *this and \p cs are dimension-incompatible.
  */
  void refine_with_constraints(const Constraint_System& cs);

  /*! \brief
    Uses a copy of the congruences in \p cgs to refine \p *this.

    \param cgs
    Contains the congruences used to refine the system of
    constraints of \p *this.

    \exception std::invalid_argument
    Thrown if \p *this and \p cgs are dimension-incompatible.
  */
  void refine_with_congruences(const Congruence_System& cgs);

  /*! \brief
    Computes the \ref Cylindrification "cylindrification" of \p *this with
    respect to space dimension \p var, assigning the result to \p *this.

    \param var
    The space dimension that will be unconstrained.

    \exception std::invalid_argument
    Thrown if \p var is not a space dimension of \p *this.
  */
  void unconstrain(Variable var);

  /*! \brief
    Computes the \ref Cylindrification "cylindrification" of \p *this with
    respect to the set of space dimensions \p to_be_unconstrained,
    assigning the result to \p *this.

    \param to_be_unconstrained
    The set of space dimension that will be unconstrained.

    \exception std::invalid_argument
    Thrown if \p *this is dimension-incompatible with one of the
    Variable objects contained in \p to_be_removed.
  */
  void unconstrain(const Variables_Set& to_be_unconstrained);

  /*! \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.

    \deprecated
    See \ref A_Note_on_the_Implementation_of_the_Operators.
  */
  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.

    \deprecated
    See \ref A_Note_on_the_Implementation_of_the_Operators.
  */
  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 a \ref Meet_Preserving_Simplification
    "meet-preserving simplification" of \p *this with respect to \p y.
    If \c false is returned, then the intersection is empty.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are topology-incompatible or
    dimension-incompatible.
  */
  bool simplify_using_context_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,
				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,
			      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,
				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,
				   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
    Assigns to \p *this the result of computing the
    \ref limited_extrapolation "limited extrapolation"
    between \p *this and \p y using the \ref BHRZ03_widening
    "BHRZ03-widening" operator.

    \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
    Assigns to \p *this the result of computing the
    \ref bounded_extrapolation "bounded extrapolation"
    between \p *this and \p y using the \ref BHRZ03_widening
    "BHRZ03-widening" operator.

    \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);

  //! Same as H79_widening_assign(y, tp).
  void widening_assign(const Polyhedron& y, unsigned* tp = 0);

  /*! \brief
    Assigns to \p *this the result of computing the
    \ref limited_extrapolation "limited extrapolation"
    between \p *this and \p y using the \ref H79_widening
    "H79-widening" operator.

    \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
    Assigns to \p *this the result of computing the
    \ref bounded_extrapolation "bounded extrapolation"
    between \p *this and \p y using the \ref H79_widening
    "H79-widening" operator.

    \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 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

  /*! \brief
    Loads from \p s an ASCII representation (as produced by
    ascii_dump(std::ostream&) const) 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
    Returns a 32-bit hash code for \p *this.

    If \p x and \p y are such that <CODE>x == y</CODE>,
    then <CODE>x.hash_code() == y.hash_code()</CODE>.
  */
  int32_t hash_code() 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.
  Bit_Matrix sat_c;

  //! The saturation matrix having generators on its columns.
  Bit_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
    ascii_dump(std::ostream&) const) 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 2035. */
#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;

  friend bool
  Parma_Polyhedra_Library::Interfaces
  ::is_necessarily_closed_for_interfaces(const Polyhedron&);

  /*! \brief
    Uses a copy of constraint \p c to refine the system of constraints
    of \p *this.

    \param c The constraint to be added. If it is dimension-incompatible
    with \p *this, the behavior is undefined.
  */
  void refine_no_check(const Constraint& c);

  //! \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;

  //! If constraints are up-to-date, obtain a simplified copy of them.
  Constraint_System simplified_constraints() 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 g
    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 g are left untouched.
  */
  bool max_min(const Linear_Expression& expr,
	       bool maximize,
	       Coefficient& ext_n, Coefficient& ext_d, bool& included,
	       Generator& g) 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,
				   Bit_Matrix& sat1,
				   Bit_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,
		       Bit_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,
			       Bit_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,
			       Bit_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,
				   Bit_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 dimension_type simplify(Linear_System& mat, Bit_Matrix& sat);

  //@} // Minimization-Related Static Member Functions

  /*! \brief
    Pointer to an array used by simplify().

    Holds (between class initialization and finalization) a pointer to
    an array, allocated with operator new[](), of
    simplify_num_saturators_size elements.
  */
  static dimension_type* simplify_num_saturators_p;

  /*! \brief
    Dimension of an array used by simplify().

    Holds (between class initialization and finalization) the size of the
    array pointed to by simplify_num_saturators_p.
  */
  static size_t simplify_num_saturators_size;

  template <typename Interval> friend class Parma_Polyhedra_Library::Box;
  template <typename T> friend class Parma_Polyhedra_Library::BD_Shape;
  template <typename T> friend class Parma_Polyhedra_Library::Octagonal_Shape;
  friend class Parma_Polyhedra_Library::Grid;
  friend class Parma_Polyhedra_Library::BHRZ03_Certificate;
  friend class Parma_Polyhedra_Library::H79_Certificate;

protected:
#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  /*! \brief
    If the poly-hull of \p *this and \p y is exact it is assigned
    to \p *this and \c true is returned, otherwise \c false is returned.

    Current implementation is based on (a variant of) Algorithm 8.1 in
      A. Bemporad, K. Fukuda, and F. D. Torrisi
      <em>Convexity Recognition of the Union of Polyhedra</em>
      Technical Report AUT00-13, ETH Zurich, 2000

    \note
    It is assumed that \p *this and \p y are topologically closed
    and dimension-compatible;
    if the assumption does not hold, the behavior is undefined.
  */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
  bool BFT00_poly_hull_assign_if_exact(const Polyhedron& y);

  bool BHZ09_poly_hull_assign_if_exact(const Polyhedron& y);
  bool BHZ09_C_poly_hull_assign_if_exact(const Polyhedron& y);
  bool BHZ09_NNC_poly_hull_assign_if_exact(const Polyhedron& y);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  //! \name Exception Throwers
  //@{
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
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,
				    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;
#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  //@} // Exception Throwers
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)

};


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 28. */
#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::space_dimension() const {
  return space_dim;
}

inline int32_t
Polyhedron::hash_code() const {
  return space_dimension() & 0x7fffffff;
}

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_discrete() const {
  return affine_dimension() == 0;
}

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 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 void
Polyhedron::widening_assign(const Polyhedron& y, unsigned* tp) {
  H79_widening_assign(y, tp);
}

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);
}

inline bool
Polyhedron::can_recycle_constraint_systems() {
  return true;
}


inline bool
Polyhedron::can_recycle_congruence_systems() {
  return false;
}

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 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 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::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);
}

inline Constraint_System
Polyhedron::simplified_constraints() const {
  assert(constraints_are_up_to_date());
  Constraint_System cs(con_sys);
  if (cs.num_pending_rows() > 0)
    cs.unset_pending_rows();
  if (has_pending_constraints() || !constraints_are_minimized())
    cs.simplify();
  return cs;
}

inline Congruence_System
Polyhedron::congruences() const {
  return Congruence_System(minimized_constraints());
}

inline Congruence_System
Polyhedron::minimized_congruences() const {
  return Congruence_System(minimized_constraints());
}

inline Grid_Generator_System
Polyhedron::minimized_grid_generators() const {
  return grid_generators();
}

inline bool
Polyhedron::add_congruence_and_minimize(const Congruence& cg) {
  add_congruence(cg);
  return minimize();
}

inline bool
Polyhedron::add_congruences_and_minimize(const Congruence_System& cgs) {
  add_congruences(cgs);
  return minimize();
}

inline void
Polyhedron::add_recycled_congruences(Congruence_System& cgs) {
  add_congruences(cgs);
}

inline bool
Polyhedron::add_recycled_congruences_and_minimize(Congruence_System& cgs) {
  return add_congruences_and_minimize(cgs);
}

/*! \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 Interfaces {

inline bool
is_necessarily_closed_for_interfaces(const Polyhedron& ph) {
  return ph.is_necessarily_closed();
}

} // namespace Interfaces

} // namespace Parma_Polyhedra_Library

namespace std {

/*! \relates Parma_Polyhedra_Library::Polyhedron */
inline void
swap(Parma_Polyhedra_Library::Polyhedron& x,
     Parma_Polyhedra_Library::Polyhedron& y) {
  x.swap(y);
}

} // namespace std

/* 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/MIP_Problem.defs.hh line 1. */
/* MIP_Problem class declaration.
*/


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


namespace Parma_Polyhedra_Library {

//! Possible outcomes of the MIP_Problem solver.
/*! \ingroup PPL_CXX_interface */
enum MIP_Problem_Status {
  //! The problem is unfeasible.
  UNFEASIBLE_MIP_PROBLEM,
  //! The problem is unbounded.
  UNBOUNDED_MIP_PROBLEM,
  //! The problem has an optimal solution.
  OPTIMIZED_MIP_PROBLEM
};

class MIP_Problem;

} // namespace Parma_Polyhedra_Library

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


/* Automatically generated from PPL source file ../src/Variables_Set.defs.hh line 29. */
#include <iosfwd>
#include <set>

namespace Parma_Polyhedra_Library {

namespace IO_Operators {

//! Output operator.
/*! \relates Parma_Polyhedra_Library::Variables_Set */
std::ostream&
operator<<(std::ostream& s, const Variables_Set& v);

} // namespace IO_Operators

} // namespace Parma_Polyhedra_Library

//! An std::set of variables' indexes.
class Parma_Polyhedra_Library::Variables_Set
  : public std::set<dimension_type> {
private:
  typedef std::set<dimension_type> Base;

public:
  //! Builds the empty set of variable indexes.
  Variables_Set();

  //! Builds the singleton set of indexes containing <CODE>v.id()</CODE>;
  explicit Variables_Set(const Variable& v);

  /*! \brief
    Builds the set of variables's indexes in the range from
    <CODE>v.id()</CODE> to <CODE>w.id()</CODE>.

    If <CODE>v.id() <= w.id()</CODE>, this constructor builds the
    set of variables' indexes
    <CODE>v.id()</CODE>, <CODE>v.id()+1</CODE>, ..., <CODE>w.id()</CODE>.
    The empty set it built otherwise.
  */
  Variables_Set(const Variable& v, const Variable& w);

  //! Returns the maximum space dimension a Variables_Set can handle.
  static dimension_type max_space_dimension();

  /*! \brief
    Returns the dimension of the smallest vector space enclosing all
    the variables whose indexes are in the set.
  */
  dimension_type space_dimension() const;

  //! Inserts the index of variavle \p v into the set.
  void insert(Variable v);
  // The `insert' method above overloads (instead of hiding) the
  // other `insert' method of std::set.
  using Base::insert;


  /*! \brief
    Loads from \p s an ASCII representation (as produced by
    ascii_dump(std::ostream&) const) 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;

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

  PPL_OUTPUT_DECLARATIONS
};

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


/* Automatically generated from PPL source file ../src/Variables_Set.inlines.hh line 27. */
#include <stdexcept>

namespace Parma_Polyhedra_Library {

inline
Variables_Set::Variables_Set()
  : Base() {
}

inline void
Variables_Set::insert(const Variable v) {
  insert(v.id());
}

inline
Variables_Set::Variables_Set(const Variable& v)
  : Base() {
  insert(v);
}

inline dimension_type
Variables_Set::max_space_dimension() {
  return Variable::max_space_dimension();
}

inline dimension_type
Variables_Set::space_dimension() const {
  reverse_iterator i = rbegin();
  return i == rend() ? 0 : *i+1;
}

inline memory_size_type
Variables_Set::external_memory_in_bytes() const {
  // We assume sets are implemented by means of red-black trees that
  // require to store the color (we assume an enum) and three pointers
  // to the parent, left and right child, respectively.
  enum color { red, black };
  return size() * (sizeof(color) + 3*sizeof(void*) + sizeof(dimension_type));
}

inline memory_size_type
Variables_Set::total_memory_in_bytes() const {
  return sizeof(*this) + external_memory_in_bytes();
}

} // namespace Parma_Polyhedra_Library

/* Automatically generated from PPL source file ../src/Variables_Set.defs.hh line 105. */

/* Automatically generated from PPL source file ../src/MIP_Problem.defs.hh line 35. */
#include <vector>
#include <deque>
#include <iosfwd>

namespace Parma_Polyhedra_Library {

namespace IO_Operators {

//! Output operator.
/*! \relates Parma_Polyhedra_Library::MIP_Problem */
std::ostream&
operator<<(std::ostream& s, const MIP_Problem& lp);

} // namespace IO_Operators

} // namespace Parma_Polyhedra_Library

//! A Mixed Integer (linear) Programming problem.
/*! \ingroup PPL_CXX_interface
  An object of this class encodes a mixed integer (linear) programming problem.
  The MIP problem is specified by providing:
   - the dimension of the vector space;
   - the feasible region, by means of a finite set of linear equality
     and non-strict inequality constraints;
   - the subset of the unknown variables that range over the integers
     (the other variables implicitly ranging over the reals);
   - the objective function, described by a Linear_Expression;
   - the optimization mode (either maximization or minimization).

  The class provides support for the (incremental) solution of the
  MIP problem based on variations of the revised simplex method and
  on branch-and-bound techniques. The result of the resolution
  process is expressed in terms of an enumeration, encoding the
  feasibility and the unboundedness of the optimization problem.
  The class supports simple feasibility tests (i.e., no optimization),
  as well as the extraction of an optimal (resp., feasible) point,
  provided the MIP_Problem is optimizable (resp., feasible).

  By exploiting the incremental nature of the solver, it is possible
  to reuse part of the computational work already done when solving
  variants of a given MIP_Problem: currently, incremental resolution
  supports the addition of space dimensions, the addition of constraints,
  the change of objective function and the change of optimization mode.
*/
class Parma_Polyhedra_Library::MIP_Problem {
public:
  //! Builds a trivial MIP problem.
  /*!
    A trivial MIP problem requires to maximize the objective function
    \f$0\f$ on a vector space under no constraints at all:
    the origin of the vector space is an optimal solution.

    \param dim
    The dimension of the vector space enclosing \p *this
    (optional argument with default value \f$0\f$).

    \exception std::length_error
    Thrown if \p dim exceeds <CODE>max_space_dimension()</CODE>.
  */
  explicit MIP_Problem(dimension_type dim = 0);

  /*! \brief
    Builds an MIP problem having space dimension \p dim
    from the sequence of constraints in the range
    \f$[\mathrm{first}, \mathrm{last})\f$,
    the objective function \p obj and optimization mode \p mode;
    those dimensions whose indices occur in \p int_vars are
    constrained to take an integer value.

    \param dim
    The dimension of the vector space enclosing \p *this.

    \param first
    An input iterator to the start of the sequence of constraints.

    \param last
    A past-the-end input iterator to the sequence of constraints.

    \param int_vars
    The set of variables' indexes that are constrained to take integer values.

    \param obj
    The objective function (optional argument with default value \f$0\f$).

    \param mode
    The optimization mode (optional argument with default value
    <CODE>MAXIMIZATION</CODE>).

    \exception std::length_error
    Thrown if \p dim exceeds <CODE>max_space_dimension()</CODE>.

    \exception std::invalid_argument
    Thrown if a constraint in the sequence is a strict inequality,
    if the space dimension of a constraint (resp., of the
    objective function or of the integer variables) or the space dimension
    of the integer variable set is strictly greater than \p dim.
  */
  template <typename In>
  MIP_Problem(dimension_type dim,
	      In first, In last,
	      const Variables_Set& int_vars,
	      const Linear_Expression& obj = Linear_Expression::zero(),
	      Optimization_Mode mode = MAXIMIZATION);

  /*! \brief
    Builds an MIP problem having space dimension \p dim
    from the sequence of constraints in the range
    \f$[\mathrm{first}, \mathrm{last})\f$,
    the objective function \p obj and optimization mode \p mode.

    \param dim
    The dimension of the vector space enclosing \p *this.

    \param first
    An input iterator to the start of the sequence of constraints.

    \param last
    A past-the-end input iterator to the sequence of constraints.

    \param obj
    The objective function (optional argument with default value \f$0\f$).

    \param mode
    The optimization mode (optional argument with default value
    <CODE>MAXIMIZATION</CODE>).

    \exception std::length_error
    Thrown if \p dim exceeds <CODE>max_space_dimension()</CODE>.

    \exception std::invalid_argument
    Thrown if a constraint in the sequence is a strict inequality
    or if the space dimension of a constraint (resp., of the
    objective function or of the integer variables) is strictly
    greater than \p dim.
  */
  template <typename In>
  MIP_Problem(dimension_type dim,
              In first, In last,
              const Linear_Expression& obj = Linear_Expression::zero(),
              Optimization_Mode mode = MAXIMIZATION);

  /*! \brief
    Builds an MIP problem having space dimension \p dim from the constraint
    system \p cs, the objective function \p obj and optimization mode \p mode.

    \param dim
    The dimension of the vector space enclosing \p *this.

    \param cs
    The constraint system defining the feasible region.

    \param obj
    The objective function (optional argument with default value \f$0\f$).

    \param mode
    The optimization mode (optional argument with default value
    <CODE>MAXIMIZATION</CODE>).

    \exception std::length_error
    Thrown if \p dim exceeds <CODE>max_space_dimension()</CODE>.

    \exception std::invalid_argument
    Thrown if the constraint system contains any strict inequality
    or if the space dimension of the constraint system (resp., the
    objective function) is strictly greater than \p dim.
  */
  MIP_Problem(dimension_type dim,
	      const Constraint_System& cs,
	      const Linear_Expression& obj = Linear_Expression::zero(),
	      Optimization_Mode mode = MAXIMIZATION);

  //! Ordinary copy-constructor.
  MIP_Problem(const MIP_Problem& y);

  //! Destructor.
  ~MIP_Problem();

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

  //! Returns the maximum space dimension an MIP_Problem can handle.
  static dimension_type max_space_dimension();

  //! Returns the space dimension of the MIP problem.
  dimension_type space_dimension() const;

  /*! \brief
    Returns a set containing all the variables' indexes constrained
    to be integral.
  */
  const Variables_Set& integer_space_dimensions() const;

private:
  //! A type alias for a sequence of constraints.
  typedef std::vector<Constraint> Constraint_Sequence;

public:
  /*! \brief
    A type alias for the read-only iterator on the constraints
    defining the feasible region.
  */
  typedef Constraint_Sequence::const_iterator const_iterator;

  /*! \brief
    Returns a read-only iterator to the first constraint defining
    the feasible region.
  */
  const_iterator constraints_begin() const;

  /*! \brief
    Returns a past-the-end read-only iterator to the sequence of
    constraints defining the feasible region.
  */
  const_iterator constraints_end() const;

  //! Returns the objective function.
  const Linear_Expression& objective_function() const;

  //! Returns the optimization mode.
  Optimization_Mode optimization_mode() const;

  //! Resets \p *this to be equal to the trivial MIP problem.
  /*!
    The space dimension is reset to \f$0\f$.
  */
  void clear();

  /*! \brief
    Adds \p m new space dimensions and embeds the old MIP problem
    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 MIP problem; they are initially unconstrained.
  */
  void add_space_dimensions_and_embed(dimension_type m);

  /*! \brief
    Sets the variables whose indexes are in set \p i_vars to be
    integer space dimensions.

    \exception std::invalid_argument
    Thrown if some index in \p i_vars does not correspond to
    a space dimension in \p *this.
  */
  void add_to_integer_space_dimensions(const Variables_Set& i_vars);

  /*! \brief
    Adds a copy of constraint \p c to the MIP problem.

    \exception std::invalid_argument
    Thrown if the constraint \p c is a strict inequality or if its space
    dimension is strictly greater than the space dimension of \p *this.
  */
  void add_constraint(const Constraint& c);

  /*! \brief
    Adds a copy of the constraints in \p cs to the MIP problem.

    \exception std::invalid_argument
    Thrown if the constraint system \p cs contains any strict inequality
    or if its space dimension is strictly greater than the space dimension
    of \p *this.
  */
  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 MIP problem is satisfiable.
  */
  bool is_satisfiable() const;

  //! Optimizes the MIP problem.
  /*!
    \return
    An MIP_Problem_Status flag indicating the outcome of the optimization
    attempt (unfeasible, unbounded or optimized problem).
  */
  MIP_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 MIP 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 MIP 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 MIP 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

  /*! \brief
    Loads from \p s an ASCII representation (as produced by
    ascii_dump(std::ostream&) const) 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;

  //! Swaps \p *this with \p y.
  void swap(MIP_Problem& y);

  //! Names of MIP problems' control parameters.
  enum Control_Parameter_Name {
    //! The pricing rule.
    PRICING
  };

  //! Possible values for MIP problem's control parameters.
  enum Control_Parameter_Value {
    //! Steepest edge pricing method, using floating points (default).
    PRICING_STEEPEST_EDGE_FLOAT,
    //! Steepest edge pricing method, using Coefficient.
    PRICING_STEEPEST_EDGE_EXACT,
    //! Textbook pricing method.
    PRICING_TEXTBOOK
  };

  //! Returns the value of the control parameter \p name.
  Control_Parameter_Value
  get_control_parameter(Control_Parameter_Name name) const;

  //! Sets control parameter \p value.
  void set_control_parameter(Control_Parameter_Value value);

private:
  //! The dimension of the vector space.
  dimension_type external_space_dim;

  /*! \brief
    The space dimension of the current (partial) solution of the
    MIP problem; it may be smaller than \p external_space_dim.
  */
  dimension_type internal_space_dim;

  //! The matrix encoding the current feasible region in tableau form.
  Matrix tableau;

  //! The working cost function.
  Row working_cost;

  //! A map between the variables of `input_cs' and `tableau'.
  /*!
    Contains all the pairs (i, j) such that mapping[i].first encodes the index
    of the column in the tableau where input_cs[i] is stored; mapping[i].second
    not a zero, encodes the split part of the tableau of input_cs[i].
    The "positive" one is represented by mapping[i].first and
    the "negative" one is represented by mapping[i].second.
  */
  std::vector<std::pair<dimension_type, dimension_type> > mapping;

  //! The current basic solution.
  std::vector<dimension_type> base;

  //! An enumerated type describing the internal status of the MIP problem.
  enum Status {
    //! The MIP problem is unsatisfiable.
    UNSATISFIABLE,
    //! The MIP problem is satisfiable; a feasible solution has been computed.
    SATISFIABLE,
    //! The MIP problem is unbounded; a feasible solution has been computed.
    UNBOUNDED,
    //! The MIP problem is optimized; an optimal solution has been computed.
    OPTIMIZED,
    /*! \brief
      The feasible region of the MIP problem has been changed by adding
      new space dimensions or new constraints; a feasible solution for
      the old feasible region is still available.
    */
    PARTIALLY_SATISFIABLE
  };

  //! The internal state of the MIP problem.
  Status status;

  // TODO: merge `status', `initialized', `pricing' and (maybe) `opt_mode'
  // into a single bitset status word, so as to save space and allow
  // for other control parameters.

  //! The pricing method in use.
  Control_Parameter_Value pricing;

  /*! \brief
    A Boolean encoding whether or not internal data structures have
    already been properly sized and populated: useful to allow for
    deeper checks in method OK().
  */
  bool initialized;

  //! The sequence of constraints describing the feasible region.
  Constraint_Sequence input_cs;

  //! The first index of `input_cs' containing a pending constraint.
  dimension_type first_pending_constraint;

  //! 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
    A set containing all the indexes of variables that are constrained
    to have an integer value.
  */
  Variables_Set i_variables;

  //! Processes the pending constraints of \p *this.
  /*!
    \return
    <CODE>true</CODE> if and only if the MIP problem is satisfiable after
    processing the pending constraints, <CODE>false</CODE> otherwise.
  */
  bool process_pending_constraints();

  /*! \brief
    Optimizes the MIP problem using the second phase of the
    primal simplex algorithm.
  */
  void second_phase();

  /*! \brief
    Assigns to \p this->tableau a simplex tableau representing the
    MIP problem, inserting into \p this->mapping the information
    that is required to recover the original MIP problem.

    \return
    <CODE>UNFEASIBLE_MIP_PROBLEM</CODE> if the constraint system contains
    any trivially unfeasible constraint (tableau was not computed);
    <CODE>UNBOUNDED_MIP_PROBLEM</CODE> if the problem is trivially unbounded
    (the computed tableau contains no constraints);
    <CODE>OPTIMIZED_MIP_PROBLEM></CODE> if the problem is neither trivially
    unfeasible nor trivially unbounded (the tableau was computed successfully).
  */
  MIP_Problem_Status
  compute_tableau(std::vector<dimension_type>& worked_out_row);

  /*! \brief
    Parses the pending constraints to gather information on
    how to resize the tableau.

    \return
    <CODE>UNSATISFIABLE</CODE> if is detected a trivially false constraint,
    <CODE>SATISFIABLE</CODE> otherwise.

    \param new_num_rows
    This will store the number of rows that has to be added to the original
    tableau.

    \param num_slack_variables
    This will store the number of slack variables that has to be added to
    the original tableau.

    \param is_tableau_constraint
    Every element of this vector will be set to <CODE>true</CODE> if the
    associated pending constraint has to be inserted in the tableau,
    <CODE>false</CODE> otherwise.

    \param nonnegative_variable
    This will encode for each variable if this one was split or not.
    Every element of this vector will be set to <CODE>true</CODE> if the
    associated variable is split, <CODE>false</CODE> otherwise.

    \param unfeasible_tableau_rows
    This will contain all the row indexes of the tableau that are no more
    satisfied after adding more constraints to \p *this.

    \param satisfied_ineqs
    This will contain all the row indexes of the tableau that are already
    satisfied by `last_generator' and do not require artificial variables to
    have a starting feasible base.

  */
  bool parse_constraints(dimension_type& new_num_rows,
			 dimension_type& num_slack_variables,
			 std::deque<bool>& is_tableau_constraint,
			 std::deque<bool>& nonnegative_variable,
			 std::vector<dimension_type>& unfeasible_tableau_rows,
			 std::deque<bool>& satisfied_ineqs);

  /*! \brief
    Computes the row index of the variable exiting the base
    of the MIP problem. Implemented with anti-cycling rule.

    \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
    Performs the pivoting operation on the tableau.

    \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 pivot(dimension_type entering_var_index,
	     dimension_type exiting_base_index);

  /*! \brief
    Computes the column index of the variable entering the base,
    using the textbook algorithm 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 returned.
  */
  dimension_type textbook_entering_index() const;

  /*! \brief
    Computes the column index of the variable entering the base,
    using an exact steepest-edge algorithm 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 returned.

    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 exact 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 coefficient by the value of
    the variable in base. Obviously the result may not be an integer, so
    we will proceed in another way: we compute the lcm of all the variables
    in base to get the good ``weight'' of each Coefficient of the tableau.
  */
  dimension_type steepest_edge_exact_entering_index() const;

  /*! \brief
    Same as steepest_edge_exact_entering_index,
    but using floating points.

    \note
    Due to rounding errors, the index of the variable entering the base
    of the MIP problem is not predictable across different architectures.
    Hence, the overall simplex computation may differ in the path taken
    to reach the optimum. Anyway, the exact final result will be computed
    for the MIP_Problem.
  */
  dimension_type steepest_edge_float_entering_index() const;

  /*! \brief
    Returns <CODE>true</CODE> if and if only the algorithm successfully
    computed a feasible solution.

    \note
    Uses an exact pricing method (either textbook or exact steepest edge),
    so that the result is deterministic across different architectures.
  */
  bool compute_simplex_using_exact_pricing();

  /*! \brief
    Returns <CODE>true</CODE> if and if only the algorithm successfully
    computed a feasible solution.

    \note
    Uses a floating point implementation of the steepest edge pricing
    method, so that the result is correct, but not deterministic across
    different architectures.
  */
  bool compute_simplex_using_steepest_edge_float();

  /*! \brief
    Drop unnecessary artificial variables from the tableau and get ready
    for the second phase of the simplex algorithm.
  */
  void erase_artificials(dimension_type begin_artificials,
			 dimension_type end_artificials);

  bool is_in_base(dimension_type var_index,
		  dimension_type& row_index) const;

  /*! \brief
    Computes a valid generator that satisfies all the constraints of the
    Linear Programming problem associated to \p *this.
  */
  void compute_generator() const;

  /*! \brief
    Merges previously split variables in the tableau if a nonnegativity
    constraint is detected.

    \param var_index
    The index of the variable that has to be merged.

    \param nonfeasible_cs
    This will contain all the row indexes that are no more satisfied by
    the computed generator after merging a variable.
  */
  void merge_split_variables(dimension_type var_index,
			      std::vector<dimension_type>& nonfeasible_cs);

  //! Returns <CODE>true</CODE> if and only if \p c is satisfied by \p g.
  static bool is_satisfied(const Constraint& c, const Generator& g);

  //! Returns <CODE>true</CODE> if and only if \p c is saturated by \p g.
  static bool is_saturated(const Constraint& c, const Generator& g);

  /*! \brief
    Returns a status that encodes the solution of the MIP problem.

    \param have_incumbent_solution
    It is used to store if the solving process has found a provisional
    optimum point.

    \param incumbent_solution_value
    Encodes the evaluated value of the provisional optimum point found.

    \param incumbent_solution_point
    If the method returns `OPTIMIZED', this will contain the optimality point.

    \param mip
    The problem that has to be solved.

    \param i_vars
    The variables that are constrained to take an integer value.
  */
  static MIP_Problem_Status solve_mip(bool& have_incumbent_solution,
				      mpq_class& incumbent_solution_value,
				      Generator& incumbent_solution_point,
				      MIP_Problem& mip,
				      const Variables_Set& i_vars);

  bool is_lp_satisfiable() const;

  /*! \brief
    Used with MIP_Problems with a non empty `i_vars',
    returns <CODE>true</CODE> if and if only a MIP problem is satisfiable,
    returns <CODE>false</CODE> otherwise.

    \param mip
    The problem that has to be solved.

    \param p
    This will encode the feasible point, only if <CODE>true</CODE> is returned.

    \param i_vars
    The variables that are constrained to take an integer value.
  */
  static bool is_mip_satisfiable(MIP_Problem& mip, Generator& p,
				 const Variables_Set& i_vars);

  /*! \brief
    Returns <CODE>true</CODE> if and if only `last_generator' satisfies all the
    integrality coditions.

    \param mip
    The MIP problem.

    \param i_vars
    The variables that are constrained to take an integer value.

    \param branching_index
    If <CODE>false</CODE> is returned, this will encode the variable index on
    which must be applied the `branch and bound' algorithm.
  */
  static bool choose_branching_variable(const MIP_Problem& mip,
					const Variables_Set& i_vars,
					dimension_type& branching_index);
};

namespace std {

//! Specializes <CODE>std::swap</CODE>.
/*! \relates Parma_Polyhedra_Library::MIP_Problem */
void swap(Parma_Polyhedra_Library::MIP_Problem& x,
	  Parma_Polyhedra_Library::MIP_Problem& y);

} // namespace std

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


/* Automatically generated from PPL source file ../src/MIP_Problem.inlines.hh line 27. */
#include <stdexcept>

namespace Parma_Polyhedra_Library {

inline dimension_type
MIP_Problem::max_space_dimension() {
  return Constraint::max_space_dimension();
}

inline dimension_type
MIP_Problem::space_dimension() const {
  return external_space_dim;
}


inline
MIP_Problem::MIP_Problem(const MIP_Problem& y)
  : external_space_dim(y.external_space_dim),
    internal_space_dim(y.internal_space_dim),
    tableau(y.tableau),
    working_cost(y.working_cost),
    mapping(y.mapping),
    base(y.base),
    status(y.status),
    pricing(y.pricing),
    initialized(y.initialized),
    input_cs(y.input_cs),
    first_pending_constraint(y.first_pending_constraint),
    input_obj_function(y.input_obj_function),
    opt_mode(y.opt_mode),
    last_generator(y.last_generator),
    i_variables(y.i_variables) {
  assert(OK());
}

inline
MIP_Problem::~MIP_Problem() {
}


inline void
MIP_Problem::set_optimization_mode(const Optimization_Mode mode) {
  if (opt_mode != mode) {
    opt_mode = mode;
    if (status == UNBOUNDED || status == OPTIMIZED)
      status = SATISFIABLE;
    assert(OK());
  }
}

inline const Linear_Expression&
MIP_Problem::objective_function() const {
  return input_obj_function;
}

inline Optimization_Mode
MIP_Problem::optimization_mode() const {
  return opt_mode;
}

inline void
MIP_Problem::optimal_value(Coefficient& num, Coefficient& den) const {
  const Generator& g = optimizing_point();
  evaluate_objective_function(g, num, den);
}

inline MIP_Problem::const_iterator
MIP_Problem::constraints_begin() const {
  return input_cs.begin();
}

inline MIP_Problem::const_iterator
MIP_Problem::constraints_end() const {
  return input_cs.end();
}

inline const Variables_Set&
MIP_Problem::integer_space_dimensions() const {
  return i_variables;
}

inline MIP_Problem::Control_Parameter_Value
MIP_Problem::get_control_parameter(Control_Parameter_Name name) const {
  used(name);
  assert(name == PRICING);
  return pricing;
}

inline void
MIP_Problem::set_control_parameter(Control_Parameter_Value value) {
  pricing = value;
}

inline void
MIP_Problem::swap(MIP_Problem& y) {
  std::swap(external_space_dim, y.external_space_dim);
  std::swap(internal_space_dim, y.internal_space_dim);
  std::swap(tableau, y.tableau);
  std::swap(working_cost, y.working_cost);
  std::swap(mapping, y.mapping);
  std::swap(initialized, y.initialized);
  std::swap(base, y.base);
  std::swap(status, y.status);
  std::swap(pricing, y.pricing);
  std::swap(input_cs, y.input_cs);
  std::swap(first_pending_constraint, y.first_pending_constraint);
  std::swap(input_obj_function, y.input_obj_function);
  std::swap(opt_mode, y.opt_mode);
  std::swap(last_generator, y.last_generator);
  std::swap(i_variables, y.i_variables);
}

inline MIP_Problem&
MIP_Problem::operator=(const MIP_Problem& y) {
  MIP_Problem tmp(y);
  swap(tmp);
  return *this;
}

inline void
MIP_Problem::clear() {
  MIP_Problem tmp;
  swap(tmp);
}

inline memory_size_type
MIP_Problem::external_memory_in_bytes() const {
  memory_size_type n
    = tableau.external_memory_in_bytes()
    + working_cost.external_memory_in_bytes()
    + input_obj_function.external_memory_in_bytes()
    + last_generator.external_memory_in_bytes();
  // Adding the external memory for `input_cs'.
  n += input_cs.capacity() * sizeof(Constraint);
  for (const_iterator i = input_cs.begin(),
	 i_end = input_cs.end(); i != i_end; ++i)
    n += (i->external_memory_in_bytes());
  // Adding the external memory for `base'.
  n += base.capacity() * sizeof(dimension_type);
  // Adding the external memory for `mapping'.
  n += mapping.capacity() * sizeof(std::pair<dimension_type, dimension_type>);
  return n;
}

inline memory_size_type
MIP_Problem::total_memory_in_bytes() const {
  return sizeof(*this) + external_memory_in_bytes();
}

} // namespace Parma_Polyhedra_Library

namespace std {

/*! \relates Parma_Polyhedra_Library::MIP_Problem */
inline void
swap(Parma_Polyhedra_Library::MIP_Problem& x,
     Parma_Polyhedra_Library::MIP_Problem& y) {
  x.swap(y);
}

} // namespace std

/* Automatically generated from PPL source file ../src/MIP_Problem.templates.hh line 1. */
/* MIP_Problem class implementation: non-inline template functions.
*/


/* Automatically generated from PPL source file ../src/MIP_Problem.templates.hh line 27. */

namespace Parma_Polyhedra_Library {

template <typename In>
MIP_Problem::MIP_Problem(const dimension_type dim,
			 In first,
			 In last,
			 const Variables_Set& int_vars,
			 const Linear_Expression& obj,
			 const Optimization_Mode mode)
  : external_space_dim(dim),
    internal_space_dim(0),
    tableau(),
    working_cost(0, Row::Flags()),
    mapping(),
    base(),
    status(PARTIALLY_SATISFIABLE),
    pricing(PRICING_STEEPEST_EDGE_FLOAT),
    initialized(false),
    input_cs(),
    first_pending_constraint(0),
    input_obj_function(obj),
    opt_mode(mode),
    last_generator(point()),
    i_variables(int_vars) {
  // Check that integer Variables_Set does not exceed the space dimension
  // of the problem.
  if (i_variables.space_dimension() > external_space_dim) {
    std::ostringstream s;
    s << "PPL::MIP_Problem::MIP_Problem"
      << "(dim, first, last, int_vars, obj, mode):\n"
      << "dim == "<< external_space_dim << " and int_vars.space_dimension() =="
      << " " << i_variables.space_dimension() << " are dimension"
      "incompatible.";
    throw std::invalid_argument(s.str());
  }

   // Check for space dimension overflow.
   if (dim > max_space_dimension())
     throw std::length_error("PPL::MIP_Problem:: MIP_Problem(dim, first, "
			     "last, int_vars, obj, mode):\n"
			     "dim exceeds the maximum allowed"
			     "space dimension.");
   // Check the objective function.
   if (obj.space_dimension() > dim) {
     std::ostringstream s;
     s << "PPL::MIP_Problem::MIP_Problem(dim, first, last,"
       << "int_vars, obj, mode):\n"
       << "obj.space_dimension() == "<< obj.space_dimension()
       << " exceeds d == "<< dim << ".";
     throw std::invalid_argument(s.str());
   }
   // Check the constraints.
   for (In i = first; i != last; ++i) {
     if (i->is_strict_inequality())
       throw std::invalid_argument("PPL::MIP_Problem::"
				   "MIP_Problem(dim, first, last, int_vars,"
				   "obj, mode):\nrange [first, last) contains"
				   "a strict inequality constraint.");
     if (i->space_dimension() > dim) {
       std::ostringstream s;
       s << "PPL::MIP_Problem::"
	 << "MIP_Problem(dim, first, last, int_vars, obj, mode):\n"
	 << "range [first, last) contains a constraint having space"
	 << "dimension  == " << i->space_dimension() << " that exceeds"
	 "this->space_dimension == " << dim << ".";
       throw std::invalid_argument(s.str());
     }
     input_cs.push_back(*i);
   }
   assert(OK());
}

template <typename In>
MIP_Problem::MIP_Problem(dimension_type dim,
			 In first, In last,
			 const Linear_Expression& obj,
			 Optimization_Mode mode)
  : external_space_dim(dim),
    internal_space_dim(0),
    tableau(),
    working_cost(0, Row::Flags()),
    mapping(),
    base(),
    status(PARTIALLY_SATISFIABLE),
    pricing(PRICING_STEEPEST_EDGE_FLOAT),
    initialized(false),
    input_cs(),
    first_pending_constraint(0),
    input_obj_function(obj),
    opt_mode(mode),
    last_generator(point()),
    i_variables() {
  // Check for space dimension overflow.
  if (dim > max_space_dimension())
    throw std::length_error("PPL::MIP_Problem::"
			    "MIP_Problem(dim, first, last, obj, mode):\n"
			    "dim exceeds the maximum allowed space "
			    "dimension.");
  // Check the objective function.
  if (obj.space_dimension() > dim) {
    std::ostringstream s;
    s << "PPL::MIP_Problem::MIP_Problem(dim, first, last,"
      << " obj, mode):\n"
      << "obj.space_dimension() == "<< obj.space_dimension()
      << " exceeds d == "<< dim << ".";
    throw std::invalid_argument(s.str());
  }
  // Check the constraints.
  for (In i = first; i != last; ++i) {
    if (i->is_strict_inequality())
      throw std::invalid_argument("PPL::MIP_Problem::"
				  "MIP_Problem(dim, first, last, obj, mode):\n"
				  "range [first, last) contains a strict "
				  "inequality constraint.");
    if (i->space_dimension() > dim) {
      std::ostringstream s;
      s << "PPL::MIP_Problem::"
	<< "MIP_Problem(dim, first, last, obj, mode):\n"
	<< "range [first, last) contains a constraint having space"
	<< "dimension" << " == " << i->space_dimension() << " that exceeds"
	"this->space_dimension == " << dim << ".";
      throw std::invalid_argument(s.str());
    }
    input_cs.push_back(*i);
  }
  assert(OK());
}

} // namespace Parma_Polyhedra_Library

/* Automatically generated from PPL source file ../src/MIP_Problem.defs.hh line 805. */

/* Automatically generated from PPL source file ../src/Polyhedron.templates.hh line 28. */
#include <algorithm>
#include <deque>

namespace Parma_Polyhedra_Library {

template <typename Interval>
Polyhedron::Polyhedron(Topology topol,
                       const Box<Interval>& box,
                       Complexity_Class)
  : 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);

  PPL_DIRTY_TEMP_COEFFICIENT(l_n);
  PPL_DIRTY_TEMP_COEFFICIENT(l_d);
  PPL_DIRTY_TEMP_COEFFICIENT(u_n);
  PPL_DIRTY_TEMP_COEFFICIENT(u_d);

  if (topol == NECESSARILY_CLOSED) {
    for (dimension_type k = space_dim; k-- > 0; ) {
      // See if we have a valid lower bound.
      bool l_closed = false;
      bool l_bounded = box.get_lower_bound(k, l_closed, l_n, l_d);
      // See if we have a valid upper bound.
      bool u_closed = false;
      bool u_bounded = box.get_upper_bound(k, u_closed, u_n, u_d);

      // 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 {
        if (l_bounded)
          // Add the constraint `l_d*v_k >= l_n'.
          con_sys.insert(l_d * Variable(k) >= l_n);
        if (u_bounded)
          // Add the constraint `u_d*v_k <= u_n'.
          con_sys.insert(u_d * Variable(k) <= u_n);
      }
    }
  }
  else {
    // topol == NOT_NECESSARILY_CLOSED
    for (dimension_type k = space_dim; k-- > 0; ) {
      // See if we have a valid lower bound.
      bool l_closed = false;
      bool l_bounded = box.get_lower_bound(k, l_closed, l_n, l_d);
      // See if we have a valid upper bound.
      bool u_closed = false;
      bool u_bounded = box.get_upper_bound(k, u_closed, u_n, u_d);

      // 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 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.has_no_rows()) {
    // 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 2715. */

/* 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 // defined(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 // defined(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/Widening_Function.defs.hh line 1. */
/* Widening_Function class declaration.
*/


/* 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 28. */

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Wraps a widening method into a function object.
/*! \ingroup PPL_CXX_interface */
#endif // defined(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 // defined(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 Pointset_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 Pointset_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 Pointset_Powerset */
template <typename PH>
inline Widening_Function<PH>
widen_fun_ref(void (PH::* wm)(const PH&, unsigned*)) {
  return Widening_Function<PH>(wm);
}

/*! \relates Pointset_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/max_space_dimension.hh line 1. */
/* Definition of functions yielding maximal space dimensions.
*/


/* 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.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/C_Polyhedron.defs.hh line 32. */

//! 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 may be
    recycled to build the polyhedron.

    \param dummy
    A dummy tag to syntactically differentiate this one
    from the other constructors.

    \exception std::invalid_argument
    Thrown if the system of constraints contains strict inequalities.
  */
  C_Polyhedron(Constraint_System& cs, Recycle_Input dummy);

  //! 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 may be
    recycled to build the polyhedron.

    \param dummy
    A dummy tag to syntactically differentiate this one
    from the other constructors.

    \exception std::invalid_argument
    Thrown if the system of generators is not empty but has no points,
    or if it contains closure points.
  */
  C_Polyhedron(Generator_System& gs, Recycle_Input dummy);

  //! 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.
  */
  explicit C_Polyhedron(const Congruence_System& cgs);

  //! Builds a 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 may be
    recycled to build the polyhedron.

    \param dummy
    A dummy tag to syntactically differentiate this one
    from the other constructors.
  */
  C_Polyhedron(Congruence_System& cgs, Recycle_Input dummy);

  /*! \brief
    Builds a C polyhedron representing the topological closure
    of the NNC polyhedron \p y.

    \param y
    The NNC polyhedron to be used;

    \param complexity
    This argument is ignored.
  */
  explicit C_Polyhedron(const NNC_Polyhedron& y,
                        Complexity_Class complexity = ANY_COMPLEXITY);

  //! Builds a C polyhedron out of a box.
  /*!
    The polyhedron inherits the space dimension of the box
    and is the most precise that includes the box.
    The algorithm used has polynomial complexity.

    \param box
    The box representing the polyhedron to be approximated;

    \param complexity
    This argument is ignored.

    \exception std::length_error
    Thrown if the space dimension of \p box exceeds the maximum allowed
    space dimension.
  */
  template <typename Interval>
  explicit C_Polyhedron(const Box<Interval>& box,
                        Complexity_Class complexity = ANY_COMPLEXITY);

  //! Builds a C polyhedron out of a BD shape.
  /*!
    The polyhedron inherits the space dimension of the BDS and is
    the most precise that includes the BDS.

    \param bd
    The BDS used to build the polyhedron.

    \param complexity
    This argument is ignored as the algorithm used has
    polynomial complexity.
  */
  template <typename U>
  explicit C_Polyhedron(const BD_Shape<U>& bd,
                        Complexity_Class complexity = ANY_COMPLEXITY);

  //! Builds a C polyhedron out of an octagonal shape.
  /*!
    The polyhedron inherits the space dimension of the octagonal shape
    and is the most precise that includes the octagonal shape.

    \param os
    The octagonal shape used to build the polyhedron.

    \param complexity
    This argument is ignored as the algorithm used has
    polynomial complexity.
  */
  template <typename U>
  explicit C_Polyhedron(const Octagonal_Shape<U>& os,
                        Complexity_Class complexity = ANY_COMPLEXITY);

  //! Builds a C polyhedron out of a grid.
  /*!
    The polyhedron inherits the space dimension of the grid
    and is the most precise that includes the grid.

    \param grid
    The grid used to build the polyhedron.

    \param complexity
    This argument is ignored as the algorithm used has
    polynomial complexity.
  */
  explicit C_Polyhedron(const Grid& grid,
                        Complexity_Class complexity = ANY_COMPLEXITY);

  //! Ordinary copy-constructor.
  /*!
    The complexity argument is ignored.
  */
  C_Polyhedron(const C_Polyhedron& y,
               Complexity_Class complexity = ANY_COMPLEXITY);

  /*! \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() {
}

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, Recycle_Input)
  : Polyhedron(NECESSARILY_CLOSED,
	       cs.space_dimension() <= max_space_dimension()
	       ? cs
	       : (throw_space_dimension_overflow(NECESSARILY_CLOSED,
						 "C_Polyhedron(cs, recycle)",
						 "the space dimension of cs "
						 "exceeds the maximum allowed "
						 "space dimension"), cs),
	       Recycle_Input()) {
}

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(gs)",
						 "the space dimension of gs "
						 "exceeds the maximum allowed "
						 "space dimension"), gs)) {
}

inline
C_Polyhedron::C_Polyhedron(Generator_System& gs, Recycle_Input)
  : Polyhedron(NECESSARILY_CLOSED,
	       gs.space_dimension() <= max_space_dimension()
	       ? gs
	       : (throw_space_dimension_overflow(NECESSARILY_CLOSED,
						 "C_Polyhedron(gs, recycle)",
						 "the space dimension of gs "
						 "exceeds the maximum allowed "
						 "space dimension"), gs),
	       Recycle_Input()) {
}

template <typename Interval>
inline
C_Polyhedron::C_Polyhedron(const Box<Interval>& box, Complexity_Class)
  : 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)) {
}

template <typename U>
inline
C_Polyhedron::C_Polyhedron(const BD_Shape<U>& bd, Complexity_Class)
  : Polyhedron(NECESSARILY_CLOSED,
	       bd.space_dimension() <= max_space_dimension()
	       ? bd.space_dimension()
	       : (throw_space_dimension_overflow(NECESSARILY_CLOSED,
						 "C_Polyhedron(bd): ",
						 "the space dimension of bd "
						 "exceeds the maximum allowed "
						 "space dimension"), 0),
               UNIVERSE) {
  add_constraints(bd.constraints());
}

template <typename U>
inline
C_Polyhedron::C_Polyhedron(const Octagonal_Shape<U>& os, Complexity_Class)
  : Polyhedron(NECESSARILY_CLOSED,
	       os.space_dimension() <= max_space_dimension()
	       ? os.space_dimension()
	       : (throw_space_dimension_overflow(NECESSARILY_CLOSED,
						 "C_Polyhedron(os): ",
						 "the space dimension of os "
						 "exceeds the maximum allowed "
						 "space dimension"), 0),
               UNIVERSE) {
  add_constraints(os.constraints());
}

inline
C_Polyhedron::C_Polyhedron(const C_Polyhedron& y, Complexity_Class)
  : 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 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 278. */

/* 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 30. */

//! 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 may be
    recycled to build the polyhedron.

    \param dummy
    A dummy tag to syntactically differentiate this one
    from the other constructors.
  */
  NNC_Polyhedron(Constraint_System& cs, Recycle_Input dummy);

  //! 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 may be
    recycled to build the polyhedron.

    \param dummy
    A dummy tag to syntactically differentiate this one
    from the other constructors.

    \exception std::invalid_argument
    Thrown if the system of generators is not empty but has no points.
  */
  NNC_Polyhedron(Generator_System& gs, Recycle_Input dummy);

  //! 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 may 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 may be
    recycled to build the polyhedron.

    \param dummy
    A dummy tag to syntactically differentiate this one
    from the other constructors.
  */
  NNC_Polyhedron(Congruence_System& cgs, Recycle_Input dummy);

  //! Builds an NNC polyhedron from the C polyhedron \p y.
  /*!
    \param y
    The C polyhedron to be used;

    \param complexity
    This argument is ignored.
  */
  explicit NNC_Polyhedron(const C_Polyhedron& y,
                          Complexity_Class complexity = ANY_COMPLEXITY);

  //! Builds an NNC polyhedron out of a box.
  /*!
    The polyhedron inherits the space dimension of the box
    and is the most precise that includes the box.

    \param box
    The box representing the polyhedron to be built;

    \param complexity
    This argument is ignored as the algorithm used has
    polynomial complexity.

    \exception std::length_error
    Thrown if the space dimension of \p box exceeds the maximum allowed
    space dimension.
  */
  template <typename Interval>
  explicit NNC_Polyhedron(const Box<Interval>& box,
                          Complexity_Class complexity = ANY_COMPLEXITY);

  //! Builds an NNC polyhedron out of a grid.
  /*!
    The polyhedron inherits the space dimension of the grid
    and is the most precise that includes the grid.

    \param grid
    The grid used to build the polyhedron.

    \param complexity
    This argument is ignored as the algorithm used has
    polynomial complexity.
  */
  explicit NNC_Polyhedron(const Grid& grid,
                          Complexity_Class complexity = ANY_COMPLEXITY);

  //! Builds a NNC polyhedron out of a BD shape.
  /*!
    The polyhedron inherits the space dimension of the BD shape
    and is the most precise that includes the BD shape.

    \param bd
    The BD shape used to build the polyhedron.

    \param complexity
    This argument is ignored as the algorithm used has
    polynomial complexity.
  */
  template <typename U>
  explicit NNC_Polyhedron(const BD_Shape<U>& bd,
                          Complexity_Class complexity = ANY_COMPLEXITY);

  //! Builds a NNC polyhedron out of an octagonal shape.
  /*!
    The polyhedron inherits the space dimension of the octagonal shape
    and is the most precise that includes the octagonal shape.

    \param os
    The octagonal shape used to build the polyhedron.

    \param complexity
    This argument is ignored as the algorithm used has
    polynomial complexity.
  */
  template <typename U>
  explicit NNC_Polyhedron(const Octagonal_Shape<U>& os,
                          Complexity_Class complexity = ANY_COMPLEXITY);

  //! Ordinary copy-constructor.
  NNC_Polyhedron(const NNC_Polyhedron& y,
                 Complexity_Class complexity = ANY_COMPLEXITY);

  /*! \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() {
}

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, Recycle_Input)
  : Polyhedron(NOT_NECESSARILY_CLOSED,
	       cs.space_dimension() <= max_space_dimension()
	       ? cs
	       : (throw_space_dimension_overflow(NOT_NECESSARILY_CLOSED,
						 "NNC_Polyhedron(cs, recycle)",
						 "the space dimension of cs "
						 "exceeds the maximum allowed "
						 "space dimension"), cs),
	       Recycle_Input()) {
}

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, Recycle_Input)
  : Polyhedron(NOT_NECESSARILY_CLOSED,
	       gs.space_dimension() <= max_space_dimension()
	       ? gs
	       : (throw_space_dimension_overflow(NOT_NECESSARILY_CLOSED,
						 "NNC_Polyhedron(gs, recycle)",
						 "the space dimension of gs "
						 "exceeds the maximum allowed "
						 "space dimension"), gs),
	       Recycle_Input()) {
}

template <typename Interval>
inline
NNC_Polyhedron::NNC_Polyhedron(const Box<Interval>& box, Complexity_Class)
  : 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)) {
}

template <typename U>
inline
NNC_Polyhedron::NNC_Polyhedron(const BD_Shape<U>& bd, Complexity_Class)
  : Polyhedron(NOT_NECESSARILY_CLOSED,
	       bd.space_dimension() <= max_space_dimension()
	       ? bd.space_dimension()
	       : (throw_space_dimension_overflow(NECESSARILY_CLOSED,
						 "NNC_Polyhedron(bd): ",
						 "the space dimension of bd "
						 "exceeds the maximum allowed "
						 "space dimension"), 0),
               UNIVERSE) {
  add_constraints(bd.constraints());
}

template <typename U>
inline
NNC_Polyhedron::NNC_Polyhedron(const Octagonal_Shape<U>& os, Complexity_Class)
  : Polyhedron(NOT_NECESSARILY_CLOSED,
	       os.space_dimension() <= max_space_dimension()
	       ? os.space_dimension()
	       : (throw_space_dimension_overflow(NECESSARILY_CLOSED,
						 "NNC_Polyhedron(os): ",
						 "the space dimension of os "
						 "exceeds the maximum allowed "
						 "space dimension"), 0),
               UNIVERSE) {
  add_constraints(os.constraints());
}

inline
NNC_Polyhedron::NNC_Polyhedron(const NNC_Polyhedron& y, Complexity_Class)
  : 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 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 254. */

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


/* Automatically generated from PPL source file ../src/Grid.defs.hh line 48. */
#include <vector>
#include <iosfwd>

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.

  The domain of grids <EM>optimally supports</EM>:
    - all (proper and non-proper) congruences;
    - tautological and inconsistent constraints;
    - linear equality constraints (i.e., non-proper congruences).

  Depending on the method, using a constraint that is not optimally
  supported by the domain will either raise an exception or
  result in a (possibly non-optimal) upward approximation.

  The domain of grids support a concept of double description similar
  to the one developed for polyhedra: hence, 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 a 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.

  A key attribute 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_grid_generator(grid_point(0*x + 0*y));
  gr.add_grid_generator(grid_line(x));
  gr.add_grid_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_grid_generator(grid_point(0*x + 0*y));
  gr.add_grid_generator(grid_point(4*x + 0*y));
  gr.add_grid_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_grid_generator(grid_point(0*x + 0*y));
  gr.add_grid_generator(grid_point(4*x + 0*y));
  gr.add_grid_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:
  //! The numeric type of coefficients.
  typedef Coefficient coefficient_type;

  //! Returns the maximum space dimension all kinds of Grid can handle.
  static dimension_type max_space_dimension();

  /*! \brief
    Returns true indicating that this domain has methods that
    can recycle congruences
  */
  static bool can_recycle_congruence_systems();

  /*! \brief
    Returns true indicating that this domain has methods that
    can recycle constraints
  */
  static bool can_recycle_constraint_systems();

  //! 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,
		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
    may be recycled to build the grid.

    \param dummy
    A dummy tag to syntactically differentiate this one
    from the other constructors.

    \exception std::length_error
    Thrown if \p num_dimensions exceeds the maximum allowed space
    dimension.
  */
  Grid(Congruence_System& cgs, Recycle_Input dummy);

  //! 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::invalid_argument
    Thrown if the constraint system \p cs contains inequality constraints.

    \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.  Its data-structures
    may be recycled to build the grid.

    \param dummy
    A dummy tag to syntactically differentiate this one
    from the other constructors.

    \exception std::invalid_argument
    Thrown if the constraint system \p cs contains inequality constraints.

    \exception std::length_error
    Thrown if \p num_dimensions exceeds the maximum allowed space
    dimension.
  */
  Grid(Constraint_System& cs, Recycle_Input dummy);

  //! Builds a grid, copying a system of grid 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 grid generators.
  /*!
    The grid inherits the space dimension of the generator system.

    \param gs
    The system of generators defining the grid.  Its data-structures
    may be recycled to build the grid.

    \param dummy
    A dummy tag to syntactically differentiate this one
    from the other constructors.

    \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.
  */
  Grid(Grid_Generator_System& gs, Recycle_Input dummy);

  //! Builds a grid out of a box.
  /*!
    The grid inherits the space dimension of the box.
    The built grid is the most precise grid that includes the box.

    \param box
    The box representing the grid to be built.

    \param complexity
    This argument is ignored as the algorithm used has
    polynomial complexity.

    \exception std::length_error
    Thrown if the space dimension of \p box exceeds the maximum
    allowed space dimension.
  */
  template <typename Interval>
  explicit Grid(const Box<Interval>& box,
                Complexity_Class complexity = ANY_COMPLEXITY);

  //! Builds a grid out of a bounded-difference shape.
  /*!
    The grid inherits the space dimension of the BDS.
    The built grid is the most precise grid that includes the BDS.

    \param bd
    The BDS representing the grid to be built.

    \param complexity
    This argument is ignored as the algorithm used has
    polynomial complexity.

    \exception std::length_error
    Thrown if the space dimension of \p bd exceeds the maximum
    allowed space dimension.
  */
  template <typename U>
  explicit Grid(const BD_Shape<U>& bd,
                Complexity_Class complexity = ANY_COMPLEXITY);

  //! Builds a grid out of an octagonal shape.
  /*!
    The grid inherits the space dimension of the octagonal shape.
    The built grid is the most precise grid that includes the octagonal shape.

    \param os
    The octagonal shape representing the grid to be built.

    \param complexity
    This argument is ignored as the algorithm used has
    polynomial complexity.

    \exception std::length_error
    Thrown if the space dimension of \p os exceeds the maximum
    allowed space dimension.
  */
  template <typename U>
  explicit Grid(const Octagonal_Shape<U>& os,
                Complexity_Class complexity = ANY_COMPLEXITY);

  //! 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);

  /*! \brief
    Builds a grid from a polyhedron using algorithms whose complexity
    does not exceed the one specified by \p complexity.
    If \p complexity is \p ANY_COMPLEXITY, then the grid built is the
    smallest one containing \p ph.

    The grid inherits the space dimension of polyhedron.

    \param ph
    The polyhedron.

    \param complexity
    The complexity class.

    \exception std::length_error
    Thrown if \p num_dimensions exceeds the maximum allowed space
    dimension.
  */
  explicit Grid(const Polyhedron& ph,
                Complexity_Class complexity = ANY_COMPLEXITY);

  //! Ordinary copy-constructor.
  /*!
    The complexity argument is ignored.
  */
  Grid(const Grid& y,
       Complexity_Class complexity = ANY_COMPLEXITY);

  /*! \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;

  /*! \brief
    Returns a system of equality constraints satisfied by \p *this
    with the same affine dimension as \p *this.
  */
  Constraint_System constraints() const;

  /*! \brief
    Returns a minimal system of equality constraints satisfied by
    \p *this with the same affine dimension as \p *this.
  */
  Constraint_System minimized_constraints() const;

  //! Returns the system of congruences.
  const Congruence_System& congruences() const;

  //! Returns the system of congruences in minimal form.
  const Congruence_System& minimized_congruences() const;

  //! Returns the system of generators.
  const Grid_Generator_System& grid_generators() const;

  //! Returns the minimized system of generators.
  const Grid_Generator_System& minimized_grid_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;

  //! 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 Generator& g) const;

  //! Returns the relations holding between \p *this and \p c.
  /*
    \exception std::invalid_argument
    Thrown if \p *this and constraint \p c 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 Constraint& c) const;

  //! Returns \c true if and only if \p *this is an empty grid.
  bool is_empty() const;

  //! Returns \c true 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.

    A grid is always topologically closed.
  */
  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;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this
    contains at least one integer point.
  */
  bool contains_integer_point() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p var is constrained in
    \p *this.

    \exception std::invalid_argument
    Thrown if \p var is not a space dimension of \p *this.
  */
  bool constrains(Variable var) 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,
		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,
		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;

  //! 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.
  */
  template <typename Interval>
  void get_covering_box(Box<Interval>& 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);

  /*! \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.

    \deprecated
    See \ref A_Note_on_the_Implementation_of_the_Operators.
  */
  bool add_congruence_and_minimize(const Congruence& c);

  /*! \brief
    Adds a copy of grid 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_grid_generator(const Grid_Generator& g);

  /*! \brief
    Adds a copy of grid 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.

    \deprecated
    See \ref A_Note_on_the_Implementation_of_the_Operators.
  */
  bool add_grid_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 the congruences in \p cgs to *this.
  /*!
    \param cgs
    The congruence system to be added to \p *this.  The congruences in
    \p cgs may be recycled.

    \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);

  /*! \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.

    \deprecated
    See \ref A_Note_on_the_Implementation_of_the_Operators.
  */
  bool add_congruences_and_minimize(const Congruence_System& cgs);

  /*! \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 to be added to \p *this.  The congruences in
    \p cgs may be recycled.

    \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.

    \deprecated
    See \ref A_Note_on_the_Implementation_of_the_Operators.
  */
  bool add_recycled_congruences_and_minimize(Congruence_System& cgs);

  /*! \brief
    Adds to \p *this a congruence equivalent to constraint \p c.

    \param c
    The constraint to be added.

    \exception std::invalid_argument
    Thrown if \p *this and \p c are dimension-incompatible
    or if constraint \p c is not optimally supported by the grid domain.
  */
  void add_constraint(const Constraint& c);

  /*! \brief
    Adds to \p *this a congruence equivalent to constraint \p c,
    also minimizing the result.

    \return
    <CODE>false</CODE> if and only if the result is empty.

    \param c
    The constraint to be added.

    \exception std::invalid_argument
    Thrown if \p *this and \p c are dimension-incompatible
    or if constraint \p c is not optimally supported by the grid domain.

    \deprecated
    See \ref A_Note_on_the_Implementation_of_the_Operators.
  */
  bool add_constraint_and_minimize(const Constraint& c);

  /*! \brief
    Adds to \p *this congruences equivalent to the constraints in \p cs.

    \param cs
    The constraints to be added.

    \exception std::invalid_argument
    Thrown if \p *this and \p cs are dimension-incompatible
    or if \p cs contains a constraint whcih is not optimally supported
    by the grid domain.
  */
  void add_constraints(const Constraint_System& cs);

  /*! \brief
    Adds to \p *this congruences equivalent to 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 be added.

    \exception std::invalid_argument
    Thrown if \p *this and \p cs are dimension-incompatible
    or if \p cs contains a constraint whcih is not optimally supported
    by the grid domain.

    \deprecated
    See \ref A_Note_on_the_Implementation_of_the_Operators.
  */
  bool add_constraints_and_minimize(const Constraint_System& cs);

  /*! \brief
    Adds to \p *this congruences equivalent to the constraints in \p cs.

    \param cs
    The constraints to be added. They may be recycled.

    \exception std::invalid_argument
    Thrown if \p *this and \p cs are dimension-incompatible
    or if \p cs contains a constraint whcih is not optimally supported
    by the grid domain.

    \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
    Adds to \p *this congruences equivalent to 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 be added. They may be recycled.

    \exception std::invalid_argument
    Thrown if \p *this and \p cs are dimension-incompatible
    or if \p cs contains a constraint whcih is not optimally supported
    by the grid domain.

    \warning
    The only assumption that can be made about \p cs upon successful
    or exceptional return is that it can be safely destroyed.

    \deprecated
    See \ref A_Note_on_the_Implementation_of_the_Operators.
  */
  bool add_recycled_constraints_and_minimize(Constraint_System& cs);

  //! Uses a copy of the congruence \p cg to refine \p *this.
  /*!
    \param cg
    The congruence used.

    \exception std::invalid_argument
    Thrown if \p *this and congruence \p cg are dimension-incompatible.
  */
  void refine_with_congruence(const Congruence& cg);

 //! Uses a copy of the congruences in \p cgs to refine \p *this.
  /*!
    \param cgs
    The congruences used.

    \exception std::invalid_argument
    Thrown if \p *this and \p cgs are dimension-incompatible.
  */
  void refine_with_congruences(const Congruence_System& cgs);

  //! Uses a copy of the constraint \p c to refine \p *this.
  /*!

    \param c
    The constraint used. If it is not an equality, it will be ignored

    \exception std::invalid_argument
    Thrown if \p *this and \p c are dimension-incompatible.
  */
  void refine_with_constraint(const Constraint& c);

  //! Uses a copy of the constraints in \p cs to refine \p *this.
  /*!
    \param cs
    The constraints used. Constraints that are not equalities are ignored.

    \exception std::invalid_argument
    Thrown if \p *this and \p cs are dimension-incompatible.
  */
  void refine_with_constraints(const 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_grid_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 to be added to \p *this.  The generators in
    \p gs may be recycled.

    \exception std::invalid_argument
    Thrown if \p *this and \p gs are dimension-incompatible.

    \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_grid_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.

    \deprecated
    See \ref A_Note_on_the_Implementation_of_the_Operators.
  */
  bool add_grid_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 to be added to \p *this.  The generators in
    \p gs may be recycled.

    \exception std::invalid_argument
    Thrown if \p *this and \p gs are dimension-incompatible.

    \warning
    The only assumption that can be made about \p gs upon successful
    or exceptional return is that it can be safely destroyed.

    \deprecated
    See \ref A_Note_on_the_Implementation_of_the_Operators.
  */
  bool add_recycled_grid_generators_and_minimize(Grid_Generator_System& gs);

  /*! \brief
    Computes the \ref Cylindrification "cylindrification" of \p *this with
    respect to space dimension \p var, assigning the result to \p *this.

    \param var
    The space dimension that will be unconstrained.

    \exception std::invalid_argument
    Thrown if \p var is not a space dimension of \p *this.
  */
  void unconstrain(Variable var);

  /*! \brief
    Computes the \ref Cylindrification "cylindrification" of \p *this with
    respect to the set of space dimensions \p to_be_unconstrained,
    assigning the result to \p *this.

    \param to_be_unconstrained
    The set of space dimension that will be unconstrained.

    \exception std::invalid_argument
    Thrown if \p *this is dimension-incompatible with one of the
    Variable objects contained in \p to_be_removed.
  */
  void unconstrain(const Variables_Set& to_be_unconstrained);

  /*! \brief
    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 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.

    \deprecated
    See \ref A_Note_on_the_Implementation_of_the_Operators.
  */
  bool intersection_assign_and_minimize(const Grid& y);

  /*! \brief
    Assigns to \p *this the least upper bound of \p *this and \p y.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are dimension-incompatible.
  */
  void upper_bound_assign(const Grid& y);

  /*! \brief
    Assigns to \p *this the least upper bound 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.

    \deprecated
    See \ref A_Note_on_the_Implementation_of_the_Operators.
  */
  bool upper_bound_assign_and_minimize(const Grid& y);

  /*! \brief
    If the upper bound 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 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 difference_assign(const Grid& y);

  /*! \brief
    Assigns to \p *this a \ref Meet_Preserving_Simplification
    "meet-preserving simplification" of \p *this with respect to \p y.
    If \c false is returned, then the intersection is empty.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are topology-incompatible or
    dimension-incompatible.
  */
  bool simplify_using_context_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 relsym
    The relation symbol where EQUAL is the symbol for a congruence
    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 zero.

    \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,
			   Relation_Symbol relsym,
			   const Linear_Expression& expr,
			   Coefficient_traits::const_reference denominator
			   = Coefficient_one(),
			   Coefficient_traits::const_reference modulus
			   = Coefficient_zero());

  /*! \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 relsym
    The relation symbol where EQUAL is the symbol for a congruence
    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 zero.

    \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,
			      Relation_Symbol relsym,
			      const Linear_Expression& expr,
			      Coefficient_traits::const_reference denominator
			      = Coefficient_one(),
			      Coefficient_traits::const_reference modulus
			      = Coefficient_zero());

  /*! \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 relsym
    The relation symbol where EQUAL is the symbol for a congruence
    relation;

    \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 zero.

    \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,
			   Relation_Symbol relsym,
			   const Linear_Expression& rhs,
			   Coefficient_traits::const_reference modulus
			   = Coefficient_zero());

  /*! \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 relsym
    The relation symbol where EQUAL is the symbol for a congruence
    relation;

    \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 zero.

    \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,
			      Relation_Symbol relsym,
			      const Linear_Expression& rhs,
			      Coefficient_traits::const_reference modulus
			      = Coefficient_zero());

  /*!
    \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 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 using congruence systems.

    \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 congruence_widening_assign(const Grid& y, unsigned* tp = NULL);

  /*! \brief
    Assigns to \p *this the result of computing the \ref Grid_Widening
    "Grid widening" between \p *this and \p y using generator systems.

    \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 generator_widening_assign(const Grid& y, unsigned* tp = NULL);

  /*! \brief
    Assigns to \p *this the result of computing the \ref Grid_Widening
    "Grid widening" between \p *this and \p y.

    This widening uses either the congruence or generator systems
    depending on which of the systems describing x and y
    are up to date and minimized.

    \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 congruence variant of
    \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_congruence_extrapolation_assign(const Grid& y,
					       const Congruence_System& cgs,
					       unsigned* tp = NULL);

  /*! \brief
    Improves the result of the generator variant 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_generator_extrapolation_assign(const Grid& y,
					      const Congruence_System& cgs,
					      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 operator==(const Grid& x, const Grid& y);

  friend class Parma_Polyhedra_Library::Grid_Certificate;

  template <typename Interval> friend class Parma_Polyhedra_Library::Box;

  //! \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

  /*! \brief
    Loads from \p s an ASCII representation (as produced by
    ascii_dump(std::ostream&) const) 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
    Returns a 32-bit hash code for \p *this.

    If \p x and \p y are such that <CODE>x == y</CODE>,
    then <CODE>x.hash_code() == y.hash_code()</CODE>.
  */
  int32_t hash_code() 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
    ascii_dump(std::ostream&) const) 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 2166. */
#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 universe or empty grid.
  /*!
    \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.
  */
  void construct(dimension_type num_dimensions, Degenerate_Element kind);

  //! 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. Its data-structures
    may be recycled to build the grid.
  */
  void construct(Congruence_System& cgs);

  //! Builds a grid from a system of grid generators.
  /*!
    The grid inherits the space dimension of the generator system.

    \param ggs
    The system of grid generators defining the grid.  Its data-structures
    may be recycled to build the grid.
  */
  void construct(Grid_Generator_System& ggs);

  //! \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 generators 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.
  void 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,
	       const char* method_call,
	       Coefficient& ext_n, Coefficient& ext_d, bool& included,
	       Generator* point = NULL) const;

  /*! \brief
    Adds the congruence \p cg to \p *this.

    \warning
    If \p cg and \p *this are dimension-incompatible,
    the behavior is undefined.
  */
  void add_congruence_no_check(const Congruence& cg);

  /*! \brief
    Uses the constraint \p c to refine \p *this.

    \param c
    The constraint to be added.

    \exception std::invalid_argument
    Thrown if c is a non-trivial inequality constraint.

    \warning
    If \p c and \p *this are dimension-incompatible,
    the behavior is undefined.
  */
  void add_constraint_no_check(const Constraint& c);

  /*! \brief
    Uses the constraint \p c to refine \p *this.

    \param c
    The constraint to be added.
    Non-trivial inequalities are ignored.

    \warning
    If \p c and \p *this are dimension-incompatible,
    the behavior is undefined.
  */
  void refine_no_check(const Constraint& c);

  //! \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;

  //! Copies widened generators from \p y to \p widened_ggs.
  void select_wider_generators(const Grid& y,
                               Grid_Generator_System& widened_ggs) 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,
			    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,
			    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.

    \param sys
    The generator system to be normalized.  It must have at least one
    row.

    \param divisor
    A reference to the initial value of the divisor.  The resulting
    value of this object is the new system divisor.

    \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 void
  normalize_divisors(Grid_Generator_System& sys,
		     Coefficient& divisor,
		     const Grid_Generator* first_point = NULL);

  //! Normalizes the divisors in \p sys.
  /*!
    Converts \p sys to an equivalent system in which the divisors are
    of equal value.

    \param sys
    The generator system to be normalized.  It must have at least one
    row.
  */
  static void
  normalize_divisors(Grid_Generator_System& sys);

  //! 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.

    \param sys
    The first of the generator systems to be normalized.

    \param gen_sys
    The second of the generator systems to be normalized.  This system
    must have at least one row and the divisors of the generators in
    this system must be equal.

    \exception std::runtime_error
    Thrown if all rows in \p gen_sys are lines and/or parameters.
  */
  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,
					    const 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,
					 const 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,
					      const Congruence& pivot,
					      dimension_type col,
					      Congruence_System& sys);

  //! Reduce column \p dim in rows preceding \p pivot_index in \p sys.
  /*!
    Required when converting (or simplifying) a congruence or generator
    system to "strong minimal form"; informally, strong minimal form means
    that, not only is the system in minimal form (ie a triangular matrix),
    but also the absolute values of the coefficients of the proper congruences
    and parameters are minimal. As a simple example, the set of congruences
    \f$\{3x \equiv_3 0, 4x + y \equiv_3 1\}\f$,
    (which is in minimal form) is equivalent to the set
    \f$\{3x \equiv_3 0, x + y \equiv_3 1\}\f$
    (which is in strong minimal form).

    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,
			     const 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,
			    dimension_type num_rows,
			    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,
			    dimension_type num_rows,
			    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

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  //! \name Exception Throwers
  //@{
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
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* g_name,
				    const 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,
				    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_constraint(const char* method,
			       const char* c_name) const;
  void throw_invalid_constraints(const char* method,
				const char* cs_name) const;
  void throw_invalid_generator(const char* method,
			       const char* g_name) const;
  void throw_invalid_generators(const char* method,
				const char* gs_name) const;
#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  //@} // Exception Throwers
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)

};


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 29. */
#include <algorithm>

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_up_to_date() {
  status.set_c_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 dimension_type
Grid::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(std::numeric_limits<dimension_type>::max() - 1,
		  std::min(Congruence_System::max_space_dimension(),
			   Grid_Generator_System::max_space_dimension()
			   )
		  );
}

inline
Grid::Grid(dimension_type num_dimensions,
	   const Degenerate_Element kind)
  : con_sys(),
    gen_sys(num_dimensions > max_space_dimension()
	    ? (throw_space_dimension_overflow("Grid(n, k)",
					      "n exceeds the maximum "
					      "allowed space dimension"),
	       0)
	    : num_dimensions) {
  construct(num_dimensions, kind);
  assert(OK());
}

inline
Grid::Grid(const Congruence_System& cgs)
  : con_sys(cgs.space_dimension() > max_space_dimension()
	    ? throw_space_dimension_overflow("Grid(cgs)",
					     "the space dimension of cgs "
					     "exceeds the maximum allowed "
					     "space dimension"), 0
	    : cgs.space_dimension()),
    gen_sys(cgs.space_dimension()) {
  Congruence_System cgs_copy(cgs);
  construct(cgs_copy);
}

inline
Grid::Grid(Congruence_System& cgs, Recycle_Input)
  : con_sys(cgs.space_dimension() > max_space_dimension()
	    ? throw_space_dimension_overflow("Grid(cgs, recycle)",
					     "the space dimension of cgs "
					     "exceeds the maximum allowed "
					     "space dimension"), 0
	    : cgs.space_dimension()),
    gen_sys(cgs.space_dimension()) {
  construct(cgs);
}

inline
Grid::Grid(const Grid_Generator_System& ggs)
  : con_sys(ggs.space_dimension() > max_space_dimension()
	    ? throw_space_dimension_overflow("Grid(ggs)",
					     "the space dimension of ggs "
					     "exceeds the maximum allowed "
					     "space dimension"), 0
	    : ggs.space_dimension()),
    gen_sys(ggs.space_dimension()) {
  Grid_Generator_System ggs_copy(ggs);
  construct(ggs_copy);
}

inline
Grid::Grid(Grid_Generator_System& ggs, Recycle_Input)
  : con_sys(ggs.space_dimension() > max_space_dimension()
	    ? throw_space_dimension_overflow("Grid(ggs, recycle)",
					     "the space dimension of ggs "
					     "exceeds the maximum allowed "
					     "space dimension"), 0
	    : ggs.space_dimension()),
    gen_sys(ggs.space_dimension()) {
  construct(ggs);
}

template <typename U>
inline
Grid::Grid(const BD_Shape<U>& bd,
           Complexity_Class)
  : con_sys(bd.space_dimension() > max_space_dimension()
	    ? throw_space_dimension_overflow("Grid(bd)",
					     "the space dimension of bd "
					     "exceeds the maximum allowed "
					     "space dimension"), 0
	    : bd.space_dimension()),
    gen_sys(bd.space_dimension()) {
  Congruence_System cgs = bd.congruences();
  construct(cgs);
}

template <typename U>
inline
Grid::Grid(const Octagonal_Shape<U>& os,
           Complexity_Class)
  : con_sys(os.space_dimension() > max_space_dimension()
	    ? throw_space_dimension_overflow("Grid(os)",
					     "the space dimension of os "
					     "exceeds the maximum allowed "
					     "space dimension"), 0
	    : os.space_dimension()),
    gen_sys(os.space_dimension()) {
  Congruence_System cgs = os.congruences();
  construct(cgs);
}

inline
Grid::~Grid() {
}

inline dimension_type
Grid::space_dimension() const {
  return space_dim;
}

inline memory_size_type
Grid::total_memory_in_bytes() const {
  return sizeof(*this) + external_memory_in_bytes();
}

inline int32_t
Grid::hash_code() const {
  return space_dimension() & 0x7fffffff;
}

inline Constraint_System
Grid::constraints() const {
    return Constraint_System(congruences());;
}

inline Constraint_System
Grid::minimized_constraints() const {
    return Constraint_System(minimized_congruences());;
}

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);
}

inline void
Grid::add_congruence(const Congruence& cg) {
  // Dimension-compatibility check.
  if (space_dim < cg.space_dimension())
    throw_dimension_incompatible("add_congruence(cg)", "cg", cg);

  if (!marked_empty())
    add_congruence_no_check(cg);
}

inline void
Grid::add_congruences(const Congruence_System& cgs) {
  // TODO: this is just an executable specification.
  // Space dimension compatibility check.
  if (space_dim < cgs.space_dimension())
    throw_dimension_incompatible("add_congruences(cgs)", "cgs", cgs);

  if (!marked_empty()) {
    Congruence_System cgs_copy = cgs;
    add_recycled_congruences(cgs_copy);
  }
}

inline bool
Grid::add_congruences_and_minimize(const Congruence_System& cgs) {
  Congruence_System cgs_copy = cgs;
  return add_recycled_congruences_and_minimize(cgs_copy);
}

inline void
Grid::refine_with_congruence(const Congruence& cg) {
  add_congruence(cg);
}

inline void
Grid::refine_with_congruences(const Congruence_System& cgs) {
  add_congruences(cgs);
}

inline bool
Grid::can_recycle_constraint_systems() {
  return true;
}

inline bool
Grid::can_recycle_congruence_systems() {
  return true;
}

inline void
Grid::add_constraint(const Constraint& c) {
  // Space dimension compatibility check.
  if (space_dim < c.space_dimension())
    throw_dimension_incompatible("add_constraint(c)", "c", c);
  if (!marked_empty())
    add_constraint_no_check(c);
}

inline bool
Grid::add_constraint_and_minimize(const Constraint& c) {
  add_constraint(c);
  return minimize();
}

inline bool
Grid::add_constraints_and_minimize(const Constraint_System& cs) {
  add_constraints(cs);
  return minimize();
}

inline void
Grid::add_recycled_constraints(Constraint_System& cs) {
  // TODO: really recycle the constraints.
  add_constraints(cs);
}

inline bool
Grid::add_recycled_constraints_and_minimize(Constraint_System& cs) {
  add_constraints(cs);
  return minimize();
}

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,
	       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,
	       Generator& point) const {
  return max_min(expr, "minimize(e, ...)", inf_n, inf_d, minimum, &point);
}

inline void
Grid::normalize_divisors(Grid_Generator_System& sys) {
  PPL_DIRTY_TEMP_COEFFICIENT(divisor);
  divisor = 1;
  normalize_divisors(sys, divisor);
}

/*! \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

namespace std {

/*! \relates Parma_Polyhedra_Library::Grid */
inline void
swap(Parma_Polyhedra_Library::Grid& x,
     Parma_Polyhedra_Library::Grid& y) {
  x.swap(y);
}

} // namespace std

/* 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 Interval>
Grid::Grid(const Box<Interval>& box,
           Complexity_Class)
  : con_sys(),
    gen_sys() {
  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();

  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 and generators according to `box'.
    PPL_DIRTY_TEMP_COEFFICIENT(l_n);
    PPL_DIRTY_TEMP_COEFFICIENT(l_d);
    PPL_DIRTY_TEMP_COEFFICIENT(u_n);
    PPL_DIRTY_TEMP_COEFFICIENT(u_d);
    gen_sys.insert(grid_point(0*Variable(space_dim-1)));
    Grid_Generator& point = gen_sys[0];
    for (dimension_type k = space_dim; k-- > 0; ) {
      bool closed = false;
      // TODO: Consider producing the system(s) in minimized form.
      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);

	    // Scale the point to use as divisor the lcm of the
	    // divisors of the existing point and the lower bound.
	    const Coefficient& point_divisor = point.divisor();
	    gcd_assign(u_n, l_d, point_divisor);
	    // `u_n' now holds the gcd.
	    exact_div_assign(u_n, point_divisor, u_n);
	    if (l_d < 0)
	      neg_assign(u_n);
	    // l_d * u_n == abs(l_d * (point_divisor / gcd(l_d, point_divisor)))
	    point.scale_to_divisor(l_d * u_n);
	    // Set dimension k of the point to the lower bound.
	    if (l_d < 0)
	      neg_assign(u_n);
	    // point[k + 1] = l_n * point_divisor / gcd(l_d, point_divisor)
	    point[k + 1] = l_n * u_n;

	    continue;
	  }
      }
      // A universe interval allows any value in dimension k.
      gen_sys.insert(grid_line(Variable(k)));
    }
    set_congruences_up_to_date();
    set_generators_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)
  : con_sys(),
    gen_sys() {

  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();

  PPL_DIRTY_TEMP_COEFFICIENT(l_n);
  PPL_DIRTY_TEMP_COEFFICIENT(l_d);

  // FIXME: consider whether or not covering boxes supporting open
  // boundaries should be disabled at compile time. If that is not
  // the case, consider if the test !box.is_topologically_closed()
  // can replace the whole loop here below.

  // Check that no finite bounds is open. This check must be done before
  // the empty test below, as an open bound might mean an empty box.
  for (dimension_type k = space_dim; k-- > 0; ) {
    bool closed = false;
    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'.
    PPL_DIRTY_TEMP_COEFFICIENT(u_n);
    PPL_DIRTY_TEMP_COEFFICIENT(u_d);
    PPL_DIRTY_TEMP_COEFFICIENT(d);
    gen_sys.insert(grid_point(0*Variable(space_dim-1)));
    Grid_Generator& point = gen_sys[0];
    for (dimension_type k = space_dim; k-- > 0; ) {
      bool closed = false;
      // TODO: Consider producing the system(s) in minimized form.
      if (box.get_lower_bound(k, closed, l_n, l_d)) {

	const Coefficient& point_divisor = point.divisor();
	assert(l_d > 0);
	assert(point_divisor > 0);
	// Use `d' to hold the gcd.
	gcd_assign(d, l_d, point_divisor);
	// Scale the point to use as divisor the lcm of the existing
	// point divisor and the divisor of the lower bound.
	exact_div_assign(d, point_divisor, d);
	// l_d * d == abs(l_d) * (point_divisor / gcd(l_d, point_divisor))
	point.scale_to_divisor(l_d * d);
	// Set dimension k of the point to the lower bound.
	// point[k + 1] = l_n * (point_divisor / gcd(l_d, point_divisor))
	point[k + 1] = l_n * 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.
	    gen_sys.insert(grid_line(Variable(k)));
	    continue;
	  }
	  assert(l_d > 0);
	  assert(u_d > 0);
	  gcd_assign(d, l_d, u_d);
	  // `d' is the gcd of the divisors.
	  exact_div_assign(l_d, l_d, d);
	  exact_div_assign(d, u_d, d);
	  l_n *= d;
	  // `l_d' is now the smallest integer expression of the size of
	  // the original l_d relative to u_d.
	  u_n = (u_n * l_d) - l_n;
	  // `u_n' is now the distance between u_n and l_n (given a
	  // divisor of lcm of l_d and u_d.
	  l_d *= u_d;
	  // `l_d' is now the lcm of the divisors.
	  con_sys.insert((l_d * Variable(k) %= l_n) / u_n);
	  gen_sys.insert(parameter(u_n * Variable(k), l_d));
	}
	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)) {
	  const Coefficient& point_divisor = point.divisor();
	  assert(u_d > 0);
	  assert(point_divisor > 0);
	  // Use `d' to hold the gcd.
	  gcd_assign(d, u_d, point_divisor);
	  // Scale the point to use as divisor the lcm of the existing
	  // point divisor and the divisor of the lower bound.
	  exact_div_assign(d, point_divisor, d);
	  // u_d * d == abs(u_d) * (point_divisor / gcd(u_d, point_divisor))
	  point.scale_to_divisor(u_d * d);
	  // Set dimension k of the point to the lower bound.
	  // point[k + 1] = u_n * (point_divisor / gcd(u_d, point_divisor))
	  point[k + 1] = u_n * 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;
	}
    }
    normalize_divisors(gen_sys);
    set_congruences_up_to_date();
    set_generators_up_to_date();
    gen_sys.set_sorted(false);
    gen_sys.unset_pending_rows();
  }

  assert(OK());
}

template <typename Interval>
void
Grid::get_covering_box(Box<Interval>& box) const {
  // Dimension-compatibility check.
  if (space_dim > box.space_dimension())
    throw_dimension_incompatible("get_covering_box(box)", "box",
				 box.space_dimension());

  Box<Interval> 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.has_no_rows());

  dimension_type num_dims = gen_sys.num_columns() - 2 /* parameter divisor */;
  dimension_type num_rows = gen_sys.num_rows();

  PPL_DIRTY_TEMP_COEFFICIENT(gcd);
  PPL_DIRTY_TEMP_COEFFICIENT(bound);

  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.add_constraint(Variable(dim) == 0);
	    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.
	dimension_type dim = num_dims;
	do {
	  gen[dim] -= point[dim];
	}
	while (dim-- > 0);
	gen.set_divisor(point.divisor());
      }
      for (dimension_type dim = num_dims; dim-- > 0; )
	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;
    const Coefficient& divisor = point.divisor();
    PPL_DIRTY_TEMP_COEFFICIENT(lower_bound);
    for (dimension_type dim = num_dims; dim-- > 0; ) {
      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, preferring 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(gcd, divisor, gcd);
	// `gcd' now holds the reduced divisor.
        new_box.add_constraint(gcd*Variable(dim) <= bound);
      }

      // Reduce the bound fraction first.
      gcd_assign(gcd, lower_bound, divisor);
      exact_div_assign(lower_bound, lower_bound, gcd);
      exact_div_assign(gcd, divisor, gcd);
      // `gcd' now holds the reduced divisor.
      new_box.add_constraint(gcd*Variable(dim) >= lower_bound);
    }
  }
  else {
    const Grid_Generator& point = gen_sys[0];
    const Coefficient& divisor = point.divisor();
    // The covering box of a single point has only lower bounds.
    for (dimension_type dim = num_dims; dim-- > 0; ) {
      // Reduce the bound fraction first.
      gcd_assign(gcd, point[dim+1], divisor);
      exact_div_assign(bound, point[dim+1], gcd);
      exact_div_assign(gcd, divisor, gcd);
      // `gcd' now holds the reduced divisor.
      new_box.add_constraint(gcd*Variable(dim) >= bound);
    }
  }

  box.swap(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;
	  // 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.
    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 = grid_generators();

  if (old_gensys.has_no_rows()) {
    // 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);
  const Coefficient& system_divisor = i->divisor();
  for (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));
}

// Needed for converting the congruence or grid_generator system
// to "strong minimal form".
template <typename M, typename R>
void
Grid::reduce_reduced(M& sys,
		     const dimension_type dim,
		     const dimension_type pivot_index,
		     const dimension_type start,
		     const dimension_type end,
		     const Dimension_Kinds& dim_kinds,
		     const bool generators) {
  R& pivot = sys[pivot_index];

  const Coefficient& pivot_dim = pivot[dim];

  if (pivot_dim == 0)
    return;

  PPL_DIRTY_TEMP_COEFFICIENT(pivot_dim_half);
  pivot_dim_half = (pivot_dim + 1) / 2;
  Dimension_Kind row_kind = dim_kinds[dim];
  Dimension_Kind line_or_equality, virtual_kind;
  int jump;
  if (generators) {
    line_or_equality = LINE;
    virtual_kind = GEN_VIRTUAL;
    jump = -1;
  }
  else {
    line_or_equality = EQUALITY;
    virtual_kind = CON_VIRTUAL;
    jump = 1;
  }

  PPL_DIRTY_TEMP_COEFFICIENT(num_rows_to_subtract);
  PPL_DIRTY_TEMP_COEFFICIENT(row_dim_remainder);
  for (dimension_type row_index = pivot_index, kinds_index = dim + jump;
       row_index-- > 0;
       kinds_index += jump) {
    // Move over any virtual rows.
    while (dim_kinds[kinds_index] == virtual_kind)
      kinds_index += jump;

    // row_kind CONGRUENCE is included as PARAMETER
    if (row_kind == line_or_equality
	|| (row_kind == PARAMETER
	    && dim_kinds[kinds_index] == PARAMETER)) {
      R& row = sys[row_index];

      const Coefficient& row_dim = row[dim];
      // num_rows_to_subtract may be positive or negative.
      num_rows_to_subtract = row_dim / pivot_dim;

      // Ensure that after subtracting num_rows_to_subtract * r_dim
      // from row_dim, -pivot_dim_half < row_dim <= pivot_dim_half.
      // E.g., if pivot[dim] = 9, then after this reduction
      // -5 < row_dim <= 5.
      row_dim_remainder = row_dim % pivot_dim;
      if (row_dim_remainder < 0) {
	if (row_dim_remainder <= -pivot_dim_half)
	  --num_rows_to_subtract;
      }
      else if (row_dim_remainder > 0 && row_dim_remainder > pivot_dim_half)
	++num_rows_to_subtract;

      // Subtract num_rows_to_subtract copies of pivot from row i.  Only the
      // entries from dim need to be subtracted, as the preceding
      // entries are all zero.
      // If num_rows_to_subtract is negative, these copies of pivot are
      // added to row i.
      if (num_rows_to_subtract != 0)
	for (dimension_type col = start; col <= end; ++col)
	  sub_mul_assign(row[col], num_rows_to_subtract, pivot[col]);
    }
  }
}

} // namespace Parma_Polyhedra_Library

/* Automatically generated from PPL source file ../src/Grid.defs.hh line 2783. */

/* Automatically generated from PPL source file ../src/Rational_Box.hh line 1. */
/* Rational_Box class declaration and implementation.
*/


/* Automatically generated from PPL source file ../src/Rational_Interval.hh line 1. */
/* Rational_Interval class declaration and implementation.
*/


/* 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/assign_or_swap.hh line 1. */
/* The assign_or_swap() utility functions.
*/


/* Automatically generated from PPL source file ../src/Has_Assign_Or_Swap.hh line 1. */
/* Has_Assign_Or_Swap classes declarations.
*/


/* Automatically generated from PPL source file ../src/Has_Assign_Or_Swap.hh line 27. */

namespace Parma_Polyhedra_Library {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \ingroup PPL_CXX_interface
  The assign_or_swap() method is not present by default.
*/
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename T, typename Enable = void>
struct Has_Assign_Or_Swap : public False {
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \ingroup PPL_CXX_interface
  The assign_or_swap() method is present if it is present (!).
*/
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename T>
struct Has_Assign_Or_Swap<T,
			  typename Enable_If_Is<void (T::*)(T& x),
						&T::assign_or_swap>::type>
  : public True {
};

} // namespace Parma_Polyhedra_Library

/* Automatically generated from PPL source file ../src/assign_or_swap.hh line 29. */

namespace Parma_Polyhedra_Library {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \ingroup PPL_CXX_interface
  If there is an assign_or_swap() method, use it.
*/
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename T>
inline typename Enable_If<Has_Assign_Or_Swap<T>::value, void>::type
assign_or_swap(T& to, T& from) {
  to.assign_or_swap(from);
}

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \ingroup PPL_CXX_interface
  If there is no assign_or_swap() method but copies are not slow, copy.
*/
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename T>
inline typename Enable_If<!Has_Assign_Or_Swap<T>::value
                          && !Slow_Copy<T>::value, void>::type
assign_or_swap(T& to, T& from) {
  to = from;
}

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \ingroup PPL_CXX_interface
  If there is no assign_or_swap() and copies are slow, delegate to std::swap().
*/
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename T>
inline typename Enable_If<!Has_Assign_Or_Swap<T>::value
                          && Slow_Copy<T>::value, void>::type
assign_or_swap(T& to, T& from) {
  std::swap(to, from);
}

} // namespace Parma_Polyhedra_Library

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


namespace Parma_Polyhedra_Library {

template <typename Boundary, typename Info>
class Interval;

} // namespace Parma_Polyhedra_Library

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


/* Automatically generated from PPL source file ../src/Boundary.defs.hh line 1. */
/* Interval boundary functions.
*/


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

namespace Parma_Polyhedra_Library {

namespace Boundary_NS {

struct Unbounded {
  Unbounded() {
  }
};

const Unbounded UNBOUNDED;

struct Property {
  enum Type {
    SPECIAL_,
    OPEN_,
    NORMALIZED_
  };
  typedef bool Value;
  static const Value default_value = true;
  static const Value unsupported_value = false;
  Property(Type t)
    : type(t) {
  }
  Type type;
};

static const Property SPECIAL(Property::SPECIAL_);
static const Property OPEN(Property::OPEN_);
static const Property NORMALIZED(Property::NORMALIZED_);

enum Boundary_Type {
  LOWER = ROUND_DOWN,
  UPPER = ROUND_UP
};

inline Rounding_Dir
round_dir_check(Boundary_Type t, bool check = false) {
  if (check)
    return static_cast<Rounding_Dir>(t | ROUND_FPU_CHECK_INEXACT);
  else
    return static_cast<Rounding_Dir>(t);
}

template <typename T, typename Info>
inline Result
special_set_boundary_infinity(Boundary_Type type, T&, Info& info) {
  assert(Info::store_special);
  info.set_boundary_property(type, SPECIAL);
  return V_EQ;
}

template <typename T, typename Info>
inline bool
special_is_boundary_infinity(Boundary_Type, const T&, const Info&) {
  return true;
}

template <typename T, typename Info>
inline bool
special_is_open(Boundary_Type, const T&, const Info&) {
  return !Info::may_contain_infinity;
}

template <typename T, typename Info>
inline bool
normal_is_open(Boundary_Type type, const T& x, const Info& info) {
  if (Info::store_open)
    return info.get_boundary_property(type, OPEN);
  else
    return !Info::store_special && !Info::may_contain_infinity
      && normal_is_boundary_infinity(type, x, info);
}

template <typename T, typename Info>
inline bool
is_open(Boundary_Type type, const T& x, const Info& info) {
  if (Info::store_open)
    return info.get_boundary_property(type, OPEN);
  else
    return !Info::may_contain_infinity
      && is_boundary_infinity(type, x, info);
}

template <typename T, typename Info>
inline Result
set_unbounded(Boundary_Type type, T& x, Info& info) {
  PPL_COMPILE_TIME_CHECK(Info::store_special
                         || std::numeric_limits<T>::is_bounded
                         || std::numeric_limits<T>::has_infinity,
                         "unbounded is not representable");
  Result r;
  if (Info::store_special)
    r = special_set_boundary_infinity(type, x, info);
  else if (type == LOWER)
    r = assign_r(x, MINUS_INFINITY, ROUND_UP);
  else
    r = assign_r(x, PLUS_INFINITY, ROUND_DOWN);
  if (r == V_EQ && !Info::may_contain_infinity)
    info.set_boundary_property(type, OPEN);
  return r;
}

template <typename T, typename Info>
inline Result
set_minus_infinity(Boundary_Type type, T& x, Info& info, bool open = false) {
  /*
  PPL_COMPILE_TIME_CHECK(Info::store_special
                         || std::numeric_limits<T>::has_infinity,
                         "minus infinity is not representable");
  */
  if (open)
    assert(type == LOWER);
  else
    assert(Info::may_contain_infinity);
  Result r;
  if (Info::store_special) {
    assert(type == LOWER);
    r = special_set_boundary_infinity(type, x, info);
  }
  else
    r = assign_r(x, MINUS_INFINITY, round_dir_check(type));
  assert(r != VC_MINUS_INFINITY);
  if (open || r != V_EQ)
    info.set_boundary_property(type, OPEN);
  return r;
}

template <typename T, typename Info>
inline Result
set_plus_infinity(Boundary_Type type, T& x, Info& info, bool open = false) {
  /*
  PPL_COMPILE_TIME_CHECK(Info::store_special
                         || std::numeric_limits<T>::has_infinity,
                         "minus infinity is not representable");
  */
  if (open)
    assert(type == UPPER);
  else
    assert(Info::may_contain_infinity);
  Result r;
  if (Info::store_special) {
    assert(type == UPPER);
    r = special_set_boundary_infinity(type, x, info);
  }
  else
    r = assign_r(x, PLUS_INFINITY, round_dir_check(type));
  assert(r != VC_MINUS_INFINITY);
  if (open || r != V_EQ)
    info.set_boundary_property(type, OPEN);
  return r;
}

template <typename T, typename Info>
inline Result
set_boundary_infinity(Boundary_Type type, T& x, Info& info, bool open = false) {
  assert(open || Info::may_contain_infinity);
  Result r;
  if (Info::store_special)
    r = special_set_boundary_infinity(type, x, info);
  else if (type == LOWER)
    r = assign_r(x, MINUS_INFINITY, round_dir_check(type));
  else
    r = assign_r(x, PLUS_INFINITY, round_dir_check(type));
  assert(r == V_EQ);
  if (open)
    info.set_boundary_property(type, OPEN);
  return r;
}

template <typename T, typename Info>
inline Result
shrink(Boundary_Type type, T& x, Info& info, bool check) {
  Result r;
  assert(!info.get_boundary_property(type, SPECIAL));
  if (type == LOWER) {
    r = info.restrict(round_dir_check(type, check), x, V_GT);
    if (r != V_GT)
      return r;
  } else {
    r = info.restrict(round_dir_check(type, check), x, V_LT);
    if (r != V_LT)
      return r;
  }
  info.set_boundary_property(type, OPEN);
  return r;
}

template <typename T, typename Info>
inline bool
is_unbounded(Boundary_Type type, const T& x, const Info& info) {
  if (Info::store_special)
    return info.get_boundary_property(type, SPECIAL)
      && special_is_boundary_infinity(type, x, info);
  else if (std::numeric_limits<T>::has_infinity) {
    if (type == LOWER)
      return Parma_Polyhedra_Library::is_minus_infinity(x);
    else
      return Parma_Polyhedra_Library::is_plus_infinity(x);
  }
  else if (std::numeric_limits<T>::is_bounded) {
    if (type == LOWER)
      return x == std::numeric_limits<T>::min();
    else
      return x == std::numeric_limits<T>::max();
  } else
    return false;
}

template <typename T, typename Info>
inline bool
normal_is_boundary_infinity(Boundary_Type type, const T& x, const Info&) {
  if (type == LOWER)
    return Parma_Polyhedra_Library::is_minus_infinity(x);
  else
    return Parma_Polyhedra_Library::is_plus_infinity(x);
}

template <typename T, typename Info>
inline bool
normal_is_reverse_infinity(Boundary_Type type, const T& x, const Info&) {
  if (!Info::may_contain_infinity)
    return false;
  else if (type == LOWER)
    return Parma_Polyhedra_Library::is_plus_infinity(x);
  else
    return Parma_Polyhedra_Library::is_minus_infinity(x);
}

template <typename T, typename Info>
inline bool
is_minus_infinity(Boundary_Type type, const T& x, const Info& info) {
  if (type == LOWER) {
    if (Info::store_special)
      return info.get_boundary_property(type, SPECIAL)
	&& special_is_boundary_infinity(type, x, info);
    else
      return normal_is_boundary_infinity(type, x, info);
  }
  else
    return !Info::store_special && normal_is_reverse_infinity(type, x, info);
}

template <typename T, typename Info>
inline bool
is_plus_infinity(Boundary_Type type, const T& x, const Info& info) {
  if (type == UPPER) {
    if (Info::store_special)
      return info.get_boundary_property(type, SPECIAL)
	&& special_is_boundary_infinity(type, x, info);
    else
      return normal_is_boundary_infinity(type, x, info);
  }
  else
    return !Info::store_special && normal_is_reverse_infinity(type, x, info);
}

template <typename T, typename Info>
inline bool
is_boundary_infinity(Boundary_Type type, const T& x, const Info& info) {
  if (Info::store_special)
    return info.get_boundary_property(type, SPECIAL)
      && special_is_boundary_infinity(type, x, info);
  else
    return normal_is_boundary_infinity(type, x, info);
}

template <typename T, typename Info>
inline bool
is_reverse_infinity(Boundary_Type type, const T& x, const Info& info) {
  return !Info::store_special
    && normal_is_reverse_infinity(type, x, info);
}

template <typename T, typename Info>
inline int
is_infinity(Boundary_Type type, const T& x, const Info& info) {
  if (is_boundary_infinity(type, x, info))
    return type == LOWER ? -1 : 1;
  else if (is_reverse_infinity(type, x, info))
    return type == UPPER ? -1 : 1;
  else
    return 0;
}

template <typename T, typename Info>
inline bool
is_boundary_infinity_closed(Boundary_Type type, const T& x, const Info& info) {
  return Info::may_contain_infinity
    && !info.get_boundary_property(type, OPEN)
    && is_boundary_infinity(type, x, info);
}

template <typename Info>
inline bool
boundary_infinity_is_open(Boundary_Type type, const Info& info) {
  return !Info::may_contain_infinity ||
    info.get_boundary_property(type, OPEN);
}

template <typename T, typename Info>
inline int
sgn_b(Boundary_Type type, const T& x, const Info& info) {
  if (info.get_boundary_property(type, SPECIAL) &&
      special_is_boundary_infinity(type, x, info))
    return type == LOWER ? -1 : 1;
  else
    // The following Parma_Polyhedra_Library:: qualification is to work
    // around a bug of GCC 4.0.x.
    return Parma_Polyhedra_Library::sgn(x);
}

template <typename T, typename Info>
inline int
sgn(Boundary_Type type, const T& x, const Info& info) {
  int sign = sgn_b(type, x, info);
  if (x == 0 && info.get_boundary_property(type, OPEN))
    return type == LOWER ? -1 : 1;
  else
    return sign;
}

template <typename T1, typename Info1, typename T2, typename Info2>
inline bool
eq(Boundary_Type type1, const T1& x1, const Info1& info1,
   Boundary_Type type2, const T2& x2, const Info2& info2) {
  if (type1 == type2) {
    if (is_open(type1, x1, info1)
	!= is_open(type2, x2, info2))
      return false;
  }
  else if (is_open(type1, x1, info1)
	   || is_open(type2, x2, info2))
    return false;
  if (is_minus_infinity(type1, x1, info1))
    return is_minus_infinity(type2, x2, info2);
  else if (is_plus_infinity(type1, x1, info1))
    return is_plus_infinity(type2, x2, info2);
  else if (is_minus_infinity(type2, x2, info2) ||
	   is_plus_infinity(type2, x2, info2))
    return false;
  else
    return equal(x1, x2);
}

template <typename T1, typename Info1, typename T2, typename Info2>
inline bool
lt(Boundary_Type type1, const T1& x1, const Info1& info1,
   Boundary_Type type2, const T2& x2, const Info2& info2) {
  if (is_open(type1, x1, info1)) {
    if (type1 == UPPER
	&& (type2 == LOWER
	    || !is_open(type2, x2, info2)))
      goto le;
  }
  else if (type2 == LOWER
	   && is_open(type2, x2, info2)) {
  le:
    if (is_minus_infinity(type1, x1, info1)
	|| is_plus_infinity(type2, x2, info2))
      return true;
    if (is_plus_infinity(type1, x1, info1)
	|| is_minus_infinity(type2, x2, info2))
      return false;
    else
      return less_or_equal(x1, x2);
  }
  if (is_plus_infinity(type1, x1, info1)
      || is_minus_infinity(type2, x2, info2))
    return false;
  if (is_minus_infinity(type1, x1, info1)
      || is_plus_infinity(type2, x2, info2))
    return true;
  else
    return less_than(x1, x2);
}

template <typename T1, typename Info1, typename T2, typename Info2>
inline bool
gt(Boundary_Type type1, const T1& x1, const Info1& info1,
   Boundary_Type type2, const T2& x2, const Info2& info2) {
  return lt(type2, x2, info2, type1, x1, info1);
}

template <typename T1, typename Info1, typename T2, typename Info2>
inline bool
le(Boundary_Type type1, const T1& x1, const Info1& info1,
   Boundary_Type type2, const T2& x2, const Info2& info2) {
  return !gt(type1, x1, info1, type2, x2, info2);
}

template <typename T1, typename Info1, typename T2, typename Info2>
inline bool
ge(Boundary_Type type1, const T1& x1, const Info1& info1,
   Boundary_Type type2, const T2& x2, const Info2& info2) {
  return !lt(type1, x1, info1, type2, x2, info2);
}

template <typename T, typename Info>
inline Result
adjust_boundary(Boundary_Type type, T& x, Info& info,
		bool open, Result r) {
  if (type == LOWER) {
    switch (r) {
    case V_NEG_OVERFLOW:
      open = true;
      /* Fall through */
    case VC_MINUS_INFINITY:
      if (!Info::store_special)
	return r;
      if (open)
	info.set_boundary_property(type, OPEN);
      return special_set_boundary_infinity(type, x, info);
    case V_GT:
      open = true;
      /* Fall through */
    case V_GE:
    case V_EQ:
      if (open)
	shrink(type, x, info, false);
      // FIXME: what to return?
      return r;
    default:
      assert(false);
      return VC_NAN;
    }
  }
  else {
    switch (r) {
    case V_POS_OVERFLOW:
      open = true;
      /* Fall through */
    case VC_PLUS_INFINITY:
      if (!Info::store_special)
	return r;
      if (open)
	info.set_boundary_property(type, OPEN);
      return special_set_boundary_infinity(type, x, info);
    case V_LT:
      open = true;
      /* Fall through */
    case V_LE:
    case V_EQ:
      if (open)
	shrink(type, x, info, false);
      // FIXME: what to return?
      return r;
    default:
      assert(false);
      return VC_NAN;
    }
  }
}

template <typename To, typename To_Info, typename T, typename Info>
inline Result
complement(Boundary_Type to_type, To& to, To_Info& to_info,
	   Boundary_Type type, const T& x, const Info& info) {
  assert(to_type != type);
  bool shrink;
  if (info.get_boundary_property(type, SPECIAL)
      && special_is_boundary_infinity(type, x, info)) {
    shrink = !special_is_open(type, x, info);
    if (type == LOWER)
      return set_minus_infinity(to_type, to, to_info, shrink);
    else
      return set_plus_infinity(to_type, to, to_info, shrink);
  }
  shrink = !normal_is_open(type, x, info);
  bool check = (To_Info::check_inexact
		|| (!shrink && (To_Info::store_open || to_info.has_restriction())));
  Result r = assign_r(to, x, round_dir_check(to_type, check));
  return adjust_boundary(to_type, to, to_info, shrink, r);
}

template <typename To, typename To_Info, typename T, typename Info>
inline Result
assign(Boundary_Type to_type, To& to, To_Info& to_info,
       Boundary_Type type, const T& x, const Info& info,
       bool shrink = false) {
  assert(to_type == type);
  if (info.get_boundary_property(type, SPECIAL)
      && special_is_boundary_infinity(type, x, info)) {
    shrink = shrink || special_is_open(type, x, info);
    return set_boundary_infinity(to_type, to, to_info, shrink);
  }
  shrink = shrink || normal_is_open(type, x, info);
  bool check = (To_Info::check_inexact
		|| (!shrink && (To_Info::store_open || to_info.has_restriction())));
  Result r = assign_r(to, x, round_dir_check(to_type, check));
  return adjust_boundary(to_type, to, to_info, shrink, r);
}

template <typename To, typename To_Info, typename T, typename Info>
inline Result
min_assign(Boundary_Type to_type, To& to, To_Info& to_info,
	   Boundary_Type type, const T& x, const Info& info) {
  if (lt(type, x, info, to_type, to, to_info)) {
    to_info.clear_boundary_properties(to_type);
    return assign(to_type, to, to_info, type, x, info);
  }
  return V_EQ;
}

template <typename To, typename To_Info, typename T1, typename Info1, typename T2, typename Info2>
inline Result
min_assign(Boundary_Type to_type, To& to, To_Info& to_info,
	   Boundary_Type type1, const T1& x1, const Info1& info1,
	   Boundary_Type type2, const T2& x2, const Info2& info2) {
  if (lt(type1, x1, info1, type2, x2, info2))
    return assign(to_type, to, to_info, type1, x1, info1);
  else
    return assign(to_type, to, to_info, type2, x2, info2);
}

template <typename To, typename To_Info, typename T, typename Info>
inline Result
max_assign(Boundary_Type to_type, To& to, To_Info& to_info,
	   Boundary_Type type, const T& x, const Info& info) {
  if (gt(type, x, info, to_type, to, to_info)) {
    to_info.clear_boundary_properties(to_type);
    return assign(to_type, to, to_info, type, x, info);
  }
  return V_EQ;
}

template <typename To, typename To_Info, typename T1, typename Info1, typename T2, typename Info2>
inline Result
max_assign(Boundary_Type to_type, To& to, To_Info& to_info,
	   Boundary_Type type1, const T1& x1, const Info1& info1,
	   Boundary_Type type2, const T2& x2, const Info2& info2) {
  if (gt(type1, x1, info1, type2, x2, info2))
    return assign(to_type, to, to_info, type1, x1, info1);
  else
    return assign(to_type, to, to_info, type2, x2, info2);
}

template <typename To, typename To_Info, typename T, typename Info>
inline Result
neg_assign(Boundary_Type to_type, To& to, To_Info& to_info,
	   Boundary_Type type, const T& x, const Info& info) {
  assert(to_type != type);
  bool shrink;
  if (info.get_boundary_property(type, SPECIAL)
      && special_is_boundary_infinity(type, x, info)) {
    shrink = special_is_open(type, x, info);
    return set_boundary_infinity(to_type, to, to_info, shrink);
  }
  shrink = normal_is_open(type, x, info);
  bool check = (To_Info::check_inexact
		|| (!shrink && (To_Info::store_open || to_info.has_restriction())));
  Result r = neg_assign_r(to, x, round_dir_check(to_type, check));
  return adjust_boundary(to_type, to, to_info, shrink, r);
}

template <typename To, typename To_Info, typename T1, typename Info1, typename T2, typename Info2>
inline Result
add_assign(Boundary_Type to_type, To& to, To_Info& to_info,
	   Boundary_Type type1, const T1& x1, const Info1& info1,
	   Boundary_Type type2, const T2& x2, const Info2& info2) {
  assert(type1 == type2);
  bool shrink;
  if (is_boundary_infinity(type1, x1, info1)) {
    shrink = boundary_infinity_is_open(type1, info1) &&
      !is_boundary_infinity_closed(type2, x2, info2);
    return set_boundary_infinity(to_type, to, to_info, shrink);
  }
  else if (is_boundary_infinity(type2, x2, info2)) {
    shrink = boundary_infinity_is_open(type2, info2) &&
      !is_boundary_infinity_closed(type1, x1, info1);
    return set_boundary_infinity(to_type, to, to_info, shrink);
  }
  shrink = normal_is_open(type1, x1, info1)
    || normal_is_open(type2, x2, info2);
  bool check = (To_Info::check_inexact
		|| (!shrink && (To_Info::store_open
				|| to_info.has_restriction())));
  // FIXME: extended handling is not needed
  Result r = add_assign_r(to, x1, x2, round_dir_check(to_type, check));
  return adjust_boundary(to_type, to, to_info, shrink, r);
}

template <typename To, typename To_Info, typename T1, typename Info1, typename T2, typename Info2>
inline Result
sub_assign(Boundary_Type to_type, To& to, To_Info& to_info,
	   Boundary_Type type1, const T1& x1, const Info1& info1,
	   Boundary_Type type2, const T2& x2, const Info2& info2) {
  assert(type1 != type2);
  bool shrink;
  if (is_boundary_infinity(type1, x1, info1)) {
    shrink = boundary_infinity_is_open(type1, info1) &&
      !is_boundary_infinity_closed(type2, x2, info2);
    return set_boundary_infinity(to_type, to, to_info, shrink);
  }
  else if (is_boundary_infinity(type2, x2, info2)) {
    shrink = boundary_infinity_is_open(type2, info2) &&
      !is_boundary_infinity_closed(type1, x1, info1);
    return set_boundary_infinity(to_type, to, to_info, shrink);
  }
  shrink = normal_is_open(type1, x1, info1)
    || normal_is_open(type2, x2, info2);
  bool check = (To_Info::check_inexact
		|| (!shrink && (To_Info::store_open
				|| to_info.has_restriction())));
  // FIXME: extended handling is not needed
  Result r = sub_assign_r(to, x1, x2, round_dir_check(to_type, check));
  return adjust_boundary(to_type, to, to_info, shrink, r);
}

template <typename To, typename To_Info, typename T1, typename Info1, typename T2, typename Info2>
inline Result
mul_assign(Boundary_Type to_type, To& to, To_Info& to_info,
	   Boundary_Type type1, const T1& x1, const Info1& info1,
	   Boundary_Type type2, const T2& x2, const Info2& info2) {
  bool shrink;
  if (is_boundary_infinity(type1, x1, info1)) {
    shrink = boundary_infinity_is_open(type1, info1) &&
      !is_boundary_infinity_closed(type2, x2, info2);
    return set_boundary_infinity(to_type, to, to_info, shrink);
  }
  else if (is_boundary_infinity(type2, x2, info2)) {
    shrink = boundary_infinity_is_open(type2, info2) &&
      !is_boundary_infinity_closed(type1, x1, info1);
    return set_boundary_infinity(to_type, to, to_info, shrink);
  }
  shrink = normal_is_open(type1, x1, info1)
    || normal_is_open(type2, x2, info2);
  bool check = (To_Info::check_inexact
		|| (!shrink && (To_Info::store_open
				|| to_info.has_restriction())));
  assert(x1 != Constant<0>::value && x2 != Constant<0>::value);
  // FIXME: extended handling is not needed
  Result r = mul_assign_r(to, x1, x2, round_dir_check(to_type, check));
  return adjust_boundary(to_type, to, to_info, shrink, r);
}

template <typename To, typename To_Info>
inline Result
set_zero(Boundary_Type to_type, To& to, To_Info& to_info, bool shrink) {
  bool check = (To_Info::check_inexact
		|| (!shrink && (To_Info::store_open || to_info.has_restriction())));
  Result r = assign_r(to, Constant<0>::value, round_dir_check(to_type, check));
  return adjust_boundary(to_type, to, to_info, shrink, r);
}

template <typename To, typename To_Info, typename T1, typename Info1, typename T2, typename Info2>
inline Result
mul_assign_z(Boundary_Type to_type, To& to, To_Info& to_info,
	     Boundary_Type type1, const T1& x1, const Info1& info1, int x1s,
	     Boundary_Type type2, const T2& x2, const Info2& info2, int x2s) {
  bool shrink;
  if (x1s != 0) {
    if (x2s != 0)
      return mul_assign(to_type, to, to_info,
			type1, x1, info1,
			type2, x2, info2);
    else
      shrink = info2.get_boundary_property(type2, OPEN);
  }
  else {
    shrink = info1.get_boundary_property(type1, OPEN)
      && (x2s != 0 || info2.get_boundary_property(type2, OPEN));
  }
  return set_zero(to_type, to, to_info, shrink);
}

template <typename To, typename To_Info, typename T1, typename Info1, typename T2, typename Info2>
inline Result
div_assign(Boundary_Type to_type, To& to, To_Info& to_info,
	   Boundary_Type type1, const T1& x1, const Info1& info1,
	   Boundary_Type type2, const T2& x2, const Info2& info2) {
  bool shrink;
  if (is_boundary_infinity(type1, x1, info1)) {
    shrink = boundary_infinity_is_open(type1, info1);
    return set_boundary_infinity(to_type, to, to_info, shrink);
  }
  else if (is_boundary_infinity(type2, x2, info2)) {
    shrink = boundary_infinity_is_open(type2, info2);
    return set_zero(to_type, to, to_info, shrink);
  }
  shrink = normal_is_open(type1, x1, info1)
    || normal_is_open(type2, x2, info2);
  bool check = (To_Info::check_inexact
		|| (!shrink && (To_Info::store_open
				|| to_info.has_restriction())));
  assert(x1 != Constant<0>::value && x2 != Constant<0>::value);
  // FIXME: extended handling is not needed
  Result r = div_assign_r(to, x1, x2, round_dir_check(to_type, check));
  return adjust_boundary(to_type, to, to_info, shrink, r);
}


template <typename To, typename To_Info, typename T1, typename Info1, typename T2, typename Info2>
inline Result
div_assign_z(Boundary_Type to_type, To& to, To_Info& to_info,
	     Boundary_Type type1, const T1& x1, const Info1& info1, int x1s,
	     Boundary_Type type2, const T2& x2, const Info2& info2, int x2s) {
  bool shrink;
  if (x1s != 0) {
    if (x2s != 0)
      return div_assign(to_type, to, to_info,
			type1, x1, info1,
			type2, x2, info2);
    else {
      // FIXME: restrictions
      return set_boundary_infinity(to_type, to, to_info, true);
    }
  }
  else {
    shrink = info1.get_boundary_property(type1, OPEN)
      && !is_boundary_infinity_closed(type2, x2, info2);
    return set_zero(to_type, to, to_info, shrink);
  }
}

} // namespace Boundary_NS

} // namespace Parma_Polyhedra_Library

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


/* Automatically generated from PPL source file ../src/Interval_Restriction.defs.hh line 32. */

namespace Parma_Polyhedra_Library {

struct Interval_Base;

template <typename T, typename Enable = void>
struct Boundary_Value {
  typedef T type;
};

template <typename T>
struct Boundary_Value<T, typename Enable_If<Is_Same_Or_Derived<Interval_Base, T>::value>::type > {
  typedef typename T::boundary_type type;
};

class Interval_Restriction_None_Base {
public:
  bool has_restriction() const {
    return false;
  }
  void normalize() const {
  }
  template <typename T>
  Result restrict(Rounding_Dir, T&, Result dir) const {
    return dir;
  }
};

inline bool
eq_restriction(const Interval_Restriction_None_Base&, const Interval_Restriction_None_Base) {
  return true;
}

template <typename T>
inline bool
contains_restriction(const Interval_Restriction_None_Base&, const T&) {
  return true;
}

template <typename T>
inline bool
assign_restriction(Interval_Restriction_None_Base&, const T&) {
  return true;
}

template <typename T1, typename T2>
inline bool
join_restriction(Interval_Restriction_None_Base&, const T1&, const T2&) {
  return true;
}

template <typename T1, typename T2>
inline bool
intersect_restriction(Interval_Restriction_None_Base&, const T1&, const T2&) {
  return true;
}

template <typename T1, typename T2>
inline bool
diff_restriction(Interval_Restriction_None_Base&, const T1&, const T2&) {
  return true;
}

template <typename T>
inline bool
neg_restriction(Interval_Restriction_None_Base&, const T&) {
  return true;
}

template <typename T1, typename T2>
inline bool
add_restriction(Interval_Restriction_None_Base&, const T1&, const T2&) {
  return true;
}

template <typename T1, typename T2>
inline bool
sub_restriction(Interval_Restriction_None_Base&, const T1&, const T2&) {
  return true;
}

template <typename T1, typename T2>
inline bool
mul_restriction(Interval_Restriction_None_Base&, const T1&, const T2&) {
  return true;
}

template <typename T1, typename T2>
inline bool
div_restriction(Interval_Restriction_None_Base&, const T1&, const T2&) {
  return true;
}

inline void
output_restriction(std::ostream&, const Interval_Restriction_None_Base&) {
}

template <typename Base>
class Interval_Restriction_None : public Interval_Restriction_None_Base,
				  public Base {
public:
  Interval_Restriction_None() {
  };
  template <typename T>
  Interval_Restriction_None(const T& init)
    : Base(init) {
  }
};

class Interval_Restriction_Integer_Base {
};

template <typename Base>
class Interval_Restriction_Integer : public Interval_Restriction_Integer_Base, public Base {
public:
  Interval_Restriction_Integer() {
  }
  void set_integer(bool v = true) {
    return set_bit(Base::bitset, integer_bit, v);
  }
  bool get_integer() const {
    return get_bit(Base::bitset, integer_bit);
  }

  const_int_nodef(integer_bit, Base::next_bit);
  const_int_nodef(next_bit, integer_bit + 1);
  bool has_restriction() const {
    return get_integer();
  }
  void normalize() const {
  }
  template <typename T>
  Result restrict(Rounding_Dir rdir, T& x, Result dir) const {
    if (!has_restriction())
      return dir;
    switch (dir) {
    case V_GT:
      if (is_integer(x))
	return add_assign_r(x, x, static_cast<T>(1), rdir);
      /* Fall through */
    case V_GE:
      return ceil_assign_r(x, x, rdir);
    case V_LT:
      if (is_integer(x))
	return sub_assign_r(x, x, static_cast<T>(1), rdir);
      /* Fall through */
    case V_LE:
      return floor_assign_r(x, x, rdir);
    default:
      assert(false);
      return dir;
    }
  }
};

class Simple_Restriction_Integer : public Interval_Restriction_Integer_Base {
public:
  Simple_Restriction_Integer(bool i)
    : integer(i) {
  }
  bool get_integer() const {
    return integer;
  }
private:
  bool integer;
};

template <typename From, typename Base, typename Enable = void>
struct Restriction_Integer;

template <typename From, typename Base>
struct Restriction_Integer<From, Base, typename Enable_If<Is_Native_Or_Checked<From>::value>::type> {
  typedef Simple_Restriction_Integer type;
  static type get(const From& x) {
    return Simple_Restriction_Integer(is_integer(x));
  }
};

template <typename From, typename Base>
struct Restriction_Integer<From, Base, typename Enable_If<Is_Same_Or_Derived<Interval_Restriction_None_Base, typename From::info_type>::value>::type> {
  typedef Simple_Restriction_Integer type;
  static type get(const From& x) {
    return Simple_Restriction_Integer(x.is_singleton() && is_integer(x.lower()));
  }
};

template <typename From, typename Base>
struct Restriction_Integer<From, Base, typename Enable_If<Is_Same_Or_Derived<Interval_Restriction_Integer_Base, typename From::info_type>::value>::type> {
  typedef Interval_Restriction_Integer<Base> type;
  static const type& get(const From& x) {
    return x.info();
  }
};

template <typename T1, typename T2>
inline typename Enable_If<Is_Same_Or_Derived<Interval_Restriction_Integer_Base, T1>::value && Is_Same_Or_Derived<Interval_Restriction_Integer_Base, T2>::value, bool>::type
eq_restriction(const T1& x, const T2& y) {
  return x.get_integer() == y.get_integer();
}

template <typename T1, typename T2>
inline typename Enable_If<Is_Same_Or_Derived<Interval_Restriction_Integer_Base, T1>::value && Is_Same_Or_Derived<Interval_Restriction_Integer_Base, T2>::value, bool>::type
contains_restriction(const T1& x, const T2& y) {
  return !x.get_integer() || y.get_integer();
}

template <typename Base, typename From>
inline bool
assign_restriction(Interval_Restriction_Integer<Base>& to, const From& x) {
  to.set_integer(Restriction_Integer<From, Base>::get(x).get_integer());
  return true;
}

template <typename Base, typename From1, typename From2>
inline bool
join_restriction(Interval_Restriction_Integer<Base>& to, const From1& x, const From2& y) {
  to.set_integer(Restriction_Integer<From1, Base>::get(x).get_integer()
		 && Restriction_Integer<From2, Base>::get(y).get_integer());
  return true;
}

template <typename Base, typename From1, typename From2>
inline bool
intersect_restriction(Interval_Restriction_Integer<Base>& to, const From1& x, const From2& y) {
  to.set_integer(Restriction_Integer<From1, Base>::get(x).get_integer()
		 || Restriction_Integer<From2, Base>::get(y).get_integer());
  return true;
}

template <typename Base, typename From1, typename From2>
inline bool
diff_restriction(Interval_Restriction_Integer<Base>& to,
		 const From1& x, const From2&) {
  to.set_integer(Restriction_Integer<From1, Base>::get(x).get_integer());
  return true;
}

template <typename Base, typename From>
inline bool
neg_restriction(Interval_Restriction_Integer<Base>& to, const From& x) {
  to.set_integer(Restriction_Integer<From, Base>::get(x).get_integer());
  return true;
}

template <typename Base, typename From1, typename From2>
inline bool
add_restriction(Interval_Restriction_Integer<Base>& to, const From1& x, const From2& y) {
  to.set_integer(Restriction_Integer<From1, Base>::get(x).get_integer()
		 && Restriction_Integer<From2, Base>::get(y).get_integer());
  return true;
}

template <typename Base, typename From1, typename From2>
inline bool
sub_restriction(Interval_Restriction_Integer<Base>& to, const From1& x, const From2& y) {
  to.set_integer(Restriction_Integer<From1, Base>::get(x).get_integer()
		 && Restriction_Integer<From2, Base>::get(y).get_integer());
  return true;
}

template <typename Base, typename From1, typename From2>
inline bool
mul_restriction(Interval_Restriction_Integer<Base>& to, const From1& x, const From2& y) {
  to.set_integer(Restriction_Integer<From1, Base>::get(x).get_integer()
		 && Restriction_Integer<From2, Base>::get(y).get_integer());
  return true;
}

template <typename Base, typename From1, typename From2>
inline bool
div_restriction(Interval_Restriction_Integer<Base>& to, const From1&, const From2&) {
  to.set_integer(false);
  return true;
}

template <typename Base>
inline void
output_restriction(std::ostream& s, const Interval_Restriction_Integer<Base>& x) {
  if (x.get_integer())
    s << "i";
}

class Interval_Restriction_Integer_Modulo_Base {
};

template <typename T, typename Base>
class Interval_Restriction_Integer_Modulo : public Interval_Restriction_Integer_Modulo_Base, public Base {
public:
  PPL_COMPILE_TIME_CHECK(std::numeric_limits<T>::is_exact,
                         "type for modulo values must be exact");
  Interval_Restriction_Integer_Modulo() {
    // FIXME: would we have speed benefits with uninitialized info?
    // (Dirty_Temp)
    clear();
  }
  bool has_restriction() const {
    return divisor != 0;
  }
  void clear() {
    remainder = 0;
    divisor = 0;
    Base::clear();
  }
  void normalize() const {
  }
  template <typename V>
  Result restrict(Rounding_Dir rdir, V& x, Result dir) const {
    if (!has_restriction())
      return dir;
    PPL_DIRTY_TEMP(V, n);
    PPL_DIRTY_TEMP(V, div);
    Result r;
    r = assign_r(div, divisor, ROUND_CHECK);
    assert(r == V_EQ);
    int s;
    r = rem_assign_r(n, x, div, ROUND_NOT_NEEDED);
    assert(r == V_EQ);
    s = sgn(n);
    switch (dir) {
    case V_GT:
      if (s >= 0) {
	r = sub_assign_r(n, div, n, ROUND_NOT_NEEDED);
	assert(r == V_EQ);
	return add_assign_r(x, x, n, rdir);
      }
      else
	return sub_assign_r(x, x, n, rdir);
    case V_GE:
      if (s > 0) {
	r = sub_assign_r(n, div, n, ROUND_NOT_NEEDED);
	assert(r == V_EQ);
	return add_assign_r(x, x, n, rdir);
      }
      else if (s < 0)
	return sub_assign_r(x, x, n, rdir);
      else
	return V_EQ;
    case V_LT:
      if (s <= 0) {
	r = add_assign_r(n, div, n, ROUND_NOT_NEEDED);
	assert(r == V_EQ);
	return sub_assign_r(x, x, n, rdir);
      }
      else
	return sub_assign_r(x, x, n, rdir);
    case V_LE:
      if (s < 0) {
	r = add_assign_r(n, div, n, ROUND_NOT_NEEDED);
	assert(r == V_EQ);
	return sub_assign_r(x, x, n, rdir);
      }
      else if (s > 0)
	return sub_assign_r(x, x, n, rdir);
      else
	return V_EQ;
    default:
      assert(false);
      return dir;
    }
  }
  void assign_or_swap(Interval_Restriction_Integer_Modulo& x) {
    Parma_Polyhedra_Library::assign_or_swap(remainder, x.remainder);
    Parma_Polyhedra_Library::assign_or_swap(divisor, x.divisor);
  }
  typedef T modulo_type;
  T remainder;
  T divisor;
};

template <typename T, typename Base>
struct Slow_Copy<Interval_Restriction_Integer_Modulo<T, Base> > : public Bool<Slow_Copy<T>::value> {};


template <typename From, typename Base>
struct Restriction_Integer<From, Base, typename Enable_If<Is_Same_Or_Derived<Interval_Restriction_Integer_Modulo_Base, typename From::info_type>::value>::type> {
  typedef Simple_Restriction_Integer type;
  static type get(const From& x) {
    return Simple_Restriction_Integer(x.info().divisor != 0);
  }
};

template <typename T>
struct Simple_Restriction_Integer_Modulo : public Interval_Restriction_Integer_Modulo_Base {
  template <typename From>
  Simple_Restriction_Integer_Modulo(const From& r, const From& d)
    : remainder(r), divisor(d) {
  }
  typedef T modulo_type;
  T remainder;
  T divisor;
};

template <typename From, typename T, typename Base, typename Enable = void>
struct Restriction_Integer_Modulo;

template <typename From, typename T, typename Base>
struct Restriction_Integer_Modulo<From, T, Base, typename Enable_If<Is_Native_Or_Checked<From>::value>::type> {
  typedef Simple_Restriction_Integer_Modulo<T> type;
  static const type& get(const From& x) {
    static const type integer(0, 1);
    static const type not_integer(0, 0);
    if (is_integer(x))
      return integer;
    else
      return not_integer;
  }
};

template <typename From, typename T, typename Base>
struct Restriction_Integer_Modulo<From, T, Base, typename Enable_If<Is_Same_Or_Derived<Interval_Restriction_None_Base, typename From::info_type>::value>::type> {
  typedef Simple_Restriction_Integer_Modulo<T> type;
  static const type& get(const From& x) {
    static const type integer(0, 1);
    static const type not_integer(0, 0);
    if (x.is_singleton() && is_integer(x.lower()))
      return integer;
    else
      return not_integer;
  }
};

template <typename From, typename T, typename Base>
struct Restriction_Integer_Modulo<From, T, Base, typename Enable_If<Is_Same_Or_Derived<Interval_Restriction_Integer_Base, typename From::info_type>::value>::type> {
  typedef Simple_Restriction_Integer_Modulo<T> type;
  static const type& get(const From& x) {
    static const type integer(0, 1);
    static const type not_integer(0, 0);
    if (x.info().get_integer())
      return integer;
    else
      return not_integer;
  }
};

template <typename From, typename T, typename Base>
struct Restriction_Integer_Modulo<From, T, Base, typename Enable_If<Is_Same_Or_Derived<Interval_Restriction_Integer_Modulo_Base, typename From::info_type>::value>::type> {
  typedef Interval_Restriction_Integer_Modulo<T, Base> type;
  static const type& get(const From& x) {
    return x.info();
  }
};

template <typename T1, typename T2>
inline typename Enable_If<Is_Same_Or_Derived<Interval_Restriction_Integer_Modulo_Base, T1>::value && Is_Same_Or_Derived<Interval_Restriction_Integer_Modulo_Base, T2>::value, bool>::type
eq_restriction(const T1& x, const T2& y) {
  return x.remainder == y.remainder
    && x.divisor == y.divisor;
}

template <typename T1, typename T2>
inline typename Enable_If<Is_Same_Or_Derived<Interval_Restriction_Integer_Modulo_Base, T1>::value && Is_Same_Or_Derived<Interval_Restriction_Integer_Modulo_Base, T2>::value, bool>::type
contains_restriction(const T1& x, const T2& y) {
  if (x.divisor == 0)
    return true;
  if (y.divisor == 0)
    return false;
  if (x.divisor == y.divisor)
    return x.remainder == y.remainder;
  PPL_DIRTY_TEMP(typename T1::modulo_type, v);
  Result r;
  r = rem_assign_r(v, y.divisor, x.divisor, ROUND_NOT_NEEDED);
  assert(r == V_EQ);
  if (v != 0)
    return false;
  r = rem_assign_r(v, y.remainder, x.divisor, ROUND_NOT_NEEDED);
  assert(r == V_EQ);
  return v == x.remainder;
}

template <typename T, typename Base>
inline bool
set_unrestricted(Interval_Restriction_Integer_Modulo<T, Base>& to) {
  to.remainder = 0;
  to.divisor = 0;
  return true;
}

template <typename T, typename Base>
inline bool
set_integer(Interval_Restriction_Integer_Modulo<T, Base>& to) {
  to.remainder = 0;
  to.divisor = 1;
  return true;
}

template <typename T, typename Base, typename From>
inline bool
assign_restriction(Interval_Restriction_Integer_Modulo<T, Base>& to, const From& x) {
  to.remainder = Restriction_Integer_Modulo<From, T, Base>::get(x).remainder;
  to.divisor = Restriction_Integer_Modulo<From, T, Base>::get(x).divisor;
  return true;
}

template <typename T, typename Base, typename From1, typename From2>
inline bool
join_restriction(Interval_Restriction_Integer_Modulo<T, Base>& to, const From1& x, const From2& y) {
  typedef Restriction_Integer_Modulo<From1, T, Base> Rx;
  const typename Rx::type& rx = Rx::get(x);
  if (rx.divisor == 0)
    return set_unrestricted(to);
  typedef Restriction_Integer_Modulo<From2, T, Base> Ry;
  const typename Ry::type& ry = Ry::get(y);
  if (ry.divisor == 0)
    return set_unrestricted(to);
  else if (rx.divisor == 1 && ry.divisor == 1
      && is_singleton(x) && is_singleton(y)) {
    PPL_DIRTY_TEMP(typename Boundary_Value<From1>::type, a);
    PPL_DIRTY_TEMP(typename Boundary_Value<From2>::type, b);
    Result r;
    r = abs_assign_r(a, f_lower(x), ROUND_CHECK);
    if (r != V_EQ)
      return set_integer(to);
    r = abs_assign_r(b, f_lower(y), ROUND_CHECK);
    if (r != V_EQ)
      return set_integer(to);
    if (a > b)
      r = sub_assign_r(a, a, b, ROUND_CHECK);
    else
      r = sub_assign_r(a, b, a, ROUND_CHECK);
    if (r != V_EQ)
      return set_integer(to);
    r = assign_r(to.divisor, a, ROUND_CHECK);
    if (r != V_EQ)
      return set_integer(to);
    r = rem_assign_r(b, b, a, ROUND_CHECK);
    if (r != V_EQ)
      return set_integer(to);
    r = assign_r(to.remainder, b, ROUND_CHECK);
    if (r != V_EQ)
      return set_integer(to);
  }
  else if (contains_restriction(rx, ry)) {
    to.remainder = rx.remainder;
    to.divisor = rx.divisor;
  }
  else if (contains_restriction(ry, rx)) {
    to.remainder = ry.remainder;
    to.divisor = ry.divisor;
  }
  else
    return set_integer(to);
  return true;
}

template <typename T, typename Base, typename From1, typename From2>
inline bool
intersect_restriction(Interval_Restriction_Integer_Modulo<T, Base>& to, const From1& x, const From2& y) {
  typedef Restriction_Integer_Modulo<From1, T, Base> Rx;
  const typename Rx::type& rx = Rx::get(x);
  typedef Restriction_Integer_Modulo<From2, T, Base> Ry;
  const typename Ry::type& ry = Ry::get(y);
  if (rx.divisor == 0) {
    to.remainder = ry.remainder;
    to.divisor = ry.divisor;
    return true;
  }
  if (ry.divisor == 0) {
    to.remainder = rx.remainder;
    to.divisor = rx.divisor;
    return true;
  }
  PPL_DIRTY_TEMP(T, g);
  Result r;
  r = gcd_assign_r(g, rx.divisor, ry.divisor, ROUND_DIRECT);
  if (r != V_EQ)
    return set_integer(to);
  PPL_DIRTY_TEMP(T, d);
  if (rx.remainder > ry.remainder)
    r = sub_assign_r(d, rx.remainder, ry.remainder, ROUND_DIRECT);
  else
    r = sub_assign_r(d, ry.remainder, rx.remainder, ROUND_DIRECT);
  if (r != V_EQ)
    return set_integer(to);
  r = div_assign_r(d, d, g, ROUND_DIRECT);
  if (r != V_EQ)
    return false;
  r = lcm_assign_r(to.divisor, rx.divisor, ry.divisor, ROUND_DIRECT);
  if (r != V_EQ)
    return set_integer(to);
  // FIXME: to be completed
  return true;
}

template <typename T, typename Base, typename From1, typename From2>
inline bool
diff_restriction(Interval_Restriction_Integer_Modulo<T, Base>& to,
		 const From1& x, const From2& y) {
  // FIXME: to be written
  return true;
}

template <typename T, typename Base, typename From>
inline bool
neg_restriction(Interval_Restriction_Integer_Modulo<T, Base>& to,
                const From& x) {
  return assign_restriction(to, x);
}

template <typename T>
inline void
addmod(T& to, const T& x, const T& y, const T& to_m, const T& y_m) {
  Result r;
  if (std::numeric_limits<T>::is_bounded) {
    r = sub_assign_r(to, y_m, y, ROUND_NOT_NEEDED);
    assert(r == V_EQ);
    if (x <= to) {
      r = add_assign_r(to, x, y, ROUND_NOT_NEEDED);
      assert(r == V_EQ);
    }
    else {
      r = sub_assign_r(to, x, to, ROUND_NOT_NEEDED);
      assert(r == V_EQ);
    }
  }
  else {
    r = add_assign_r(to, x, y, ROUND_NOT_NEEDED);
    assert(r == V_EQ);
  }
  r = rem_assign_r(to, to, to_m, ROUND_NOT_NEEDED);
  assert(r == V_EQ);
}

template <typename M, typename T>
inline bool
assign_rem(M& rem, const T& n, const M& div) {
  PPL_DIRTY_TEMP(T, divisor);
  PPL_DIRTY_TEMP(T, remainder);
  Result r;
  r = assign_r(divisor, div, ROUND_CHECK);
  if (r != V_EQ)
    return false;
  r = rem_assign_r(remainder, n, divisor, ROUND_CHECK);
  if (r != V_EQ)
    return false;
  if (sgn(remainder) < 0) {
    r = add_assign_r(remainder, remainder, divisor, ROUND_CHECK);
    if (r != V_EQ)
      return false;
  }
  r = assign_r(rem, remainder, ROUND_CHECK);
  return r == V_EQ;
}


template <typename T, typename Base, typename From1, typename From2>
inline bool
add_restriction(Interval_Restriction_Integer_Modulo<T, Base>& to, const From1& x, const From2& y) {
  typedef Restriction_Integer_Modulo<From1, T, Base> Rx;
  const typename Rx::type& rx = Rx::get(x);
  if (rx.divisor == 0)
    return set_unrestricted(to);
  typedef Restriction_Integer_Modulo<From2, T, Base> Ry;
  const typename Ry::type& ry = Ry::get(y);
  if (ry.divisor == 0)
    return set_unrestricted(to);
  Result r;
  PPL_DIRTY_TEMP(T, rem);
  if (is_singleton(x)) {
    if (is_singleton(y))
      return set_integer(to);
    if (!assign_rem(rem, f_lower(x), ry.divisor))
      return set_integer(to);
    r = assign_r(to.divisor, ry.divisor, ROUND_NOT_NEEDED);
    assert(r == V_EQ);
    addmod(to.remainder, rem, ry.remainder, to.divisor, ry.divisor);
  }
  else if (is_singleton(y)) {
    if (!assign_rem(rem, f_lower(y), rx.divisor))
      return set_integer(to);
    r = assign_r(to.divisor, rx.divisor, ROUND_NOT_NEEDED);
    assert(r == V_EQ);
    addmod(to.remainder, rx.remainder, rem, to.divisor, to.divisor);
  }
  else {
    r = gcd_assign_r(to.divisor, rx.divisor, ry.divisor, ROUND_NOT_NEEDED);
    assert(r == V_EQ);
    addmod(to.remainder, rx.remainder, ry.remainder, to.divisor, ry.divisor);
  }
  return true;
}

template <typename T>
inline void
submod(T& to, const T& x, const T& y, const T& to_m, const T& y_m) {
  Result r;
  if (x >= y) {
    r = sub_assign_r(to, x, y, ROUND_NOT_NEEDED);
    assert(r == V_EQ);
  }
  else {
    r = sub_assign_r(to, y_m, y, ROUND_NOT_NEEDED);
    assert(r == V_EQ);
    r = add_assign_r(to, x, to, ROUND_NOT_NEEDED);
    assert(r == V_EQ);
  }
  r = rem_assign_r(to, to, to_m, ROUND_NOT_NEEDED);
  assert(r == V_EQ);
}

template <typename T, typename Base, typename From1, typename From2>
inline bool
sub_restriction(Interval_Restriction_Integer_Modulo<T, Base>& to, const From1& x, const From2& y) {
  typedef Restriction_Integer_Modulo<From1, T, Base> Rx;
  const typename Rx::type& rx = Rx::get(x);
  if (rx.divisor == 0)
    return set_unrestricted(to);
  typedef Restriction_Integer_Modulo<From2, T, Base> Ry;
  const typename Ry::type& ry = Ry::get(y);
  if (ry.divisor == 0)
    return set_unrestricted(to);
  Result r;
  PPL_DIRTY_TEMP(T, rem);
  if (is_singleton(x)) {
    if (is_singleton(y))
      return set_integer(to);
    if (!assign_rem(rem, f_lower(x), ry.divisor))
      return set_integer(to);
    r = assign_r(to.divisor, ry.divisor, ROUND_NOT_NEEDED);
    assert(r == V_EQ);
    submod(to.remainder, rem, ry.remainder, to.divisor, ry.divisor);
  }
  else if (is_singleton(y)) {
    if (!assign_rem(rem, f_lower(y), rx.divisor))
      return set_integer(to);
    r = assign_r(to.divisor, rx.divisor, ROUND_NOT_NEEDED);
    assert(r == V_EQ);
    submod(to.remainder, rx.remainder, rem, to.divisor, to.divisor);
  }
  else {
    r = gcd_assign_r(to.divisor, rx.divisor, ry.divisor, ROUND_NOT_NEEDED);
    assert(r == V_EQ);
    submod(to.remainder, rx.remainder, ry.remainder, to.divisor, ry.divisor);
  }
  return true;
}

template <typename T>
inline void
mulmod(T& to, const T& x, const T& y, const T& to_m) {
  Result r;
  if (std::numeric_limits<T>::is_bounded) {
    PPL_DIRTY_TEMP0(mpz_class, a);
    PPL_DIRTY_TEMP0(mpz_class, b);
    r = assign_r(a, x, ROUND_NOT_NEEDED);
    assert(r == V_EQ);
    r = assign_r(b, y, ROUND_NOT_NEEDED);
    assert(r == V_EQ);
    r = mul_assign_r(a, a, b, ROUND_NOT_NEEDED);
    assert(r == V_EQ);
    r = assign_r(b, to_m, ROUND_NOT_NEEDED);
    assert(r == V_EQ);
    r = rem_assign_r(a, a, b, ROUND_NOT_NEEDED);
    assert(r == V_EQ);
    r = assign_r(to, a, ROUND_NOT_NEEDED);
    assert(r == V_EQ);
  }
  else {
    r = mul_assign_r(to, x, y, ROUND_NOT_NEEDED);
    assert(r == V_EQ);
    r = rem_assign_r(to, to, to_m, ROUND_NOT_NEEDED);
    assert(r == V_EQ);
  }
}


template <typename T, typename Base, typename From1, typename From2>
inline bool
mul_restriction(Interval_Restriction_Integer_Modulo<T, Base>& to, const From1& x, const From2& y) {
  typedef Restriction_Integer_Modulo<From1, T, Base> Rx;
  const typename Rx::type& rx = Rx::get(x);
  if (rx.divisor == 0)
    return set_unrestricted(to);
  typedef Restriction_Integer_Modulo<From2, T, Base> Ry;
  const typename Ry::type& ry = Ry::get(y);
  if (ry.divisor == 0)
    return set_unrestricted(to);
  Result r;
  PPL_DIRTY_TEMP(T, mul);
  if (is_singleton(x)) {
    if (is_singleton(y))
      return set_integer(to);
    PPL_DIRTY_TEMP(typename Boundary_Value<From1>::type, n);
    r = abs_assign_r(n, f_lower(x), ROUND_CHECK);
    if (r != V_EQ)
      return set_integer(to);
    r = assign_r(mul, n, ROUND_CHECK);
    if (r != V_EQ)
      return set_integer(to);
    r = mul_assign_r(to.remainder, mul, ry.remainder, ROUND_NOT_NEEDED);
    if (r != V_EQ)
      return set_integer(to);
    r = mul_assign_r(to.divisor, mul, ry.divisor, ROUND_NOT_NEEDED);
    if (r != V_EQ)
      return set_integer(to);
  }
  else if (is_singleton(y)) {
    PPL_DIRTY_TEMP(typename Boundary_Value<From2>::type, n);
    r = abs_assign_r(n, f_lower(y), ROUND_CHECK);
    if (r != V_EQ)
      return set_integer(to);
    r = assign_r(mul, n, ROUND_CHECK);
    if (r != V_EQ)
      return set_integer(to);
    r = mul_assign_r(to.remainder, rx.remainder, mul, ROUND_NOT_NEEDED);
    if (r != V_EQ)
      return set_integer(to);
    r = mul_assign_r(to.divisor, rx.divisor, mul, ROUND_NOT_NEEDED);
    if (r != V_EQ)
      return set_integer(to);
  }
  else {
    r = gcd_assign_r(to.divisor, rx.divisor, ry.divisor, ROUND_NOT_NEEDED);
    assert(r == V_EQ);
    mulmod(to.remainder, rx.remainder, ry.remainder, to.divisor);
  }
  return true;
}

template <typename T, typename Base, typename From1, typename From2>
inline bool
div_restriction(Interval_Restriction_Integer_Modulo<T, Base>& to,
                const From1& x, const From2& y) {
  if (is_singleton(y)) {
    if (is_singleton(x)) {
      // FIXME: to be written
    }
  }
  return set_unrestricted(to);
}

template <typename T, typename Base>
inline void
output_restriction(std::ostream& s, const Interval_Restriction_Integer_Modulo<T, Base>& x) {
  if (x.divisor == 1)
    s << "i";
  else if (x.divisor != 0)
    s << "{" << x.remainder << "%" << x.divisor << "}";
}

}

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

#include <iostream>

namespace Parma_Polyhedra_Library {

namespace Interval_NS {

struct Property {
  enum Type {
    CARDINALITY_0_,
    CARDINALITY_1_,
    CARDINALITY_IS_
  };
  typedef bool Value;
  static const Value default_value = true;
  static const Value unsupported_value = false;
  Property(Type t)
    : type(t) {
  }
  Type type;
};

const Property CARDINALITY_0(Property::CARDINALITY_0_);
const Property CARDINALITY_1(Property::CARDINALITY_1_);
const Property CARDINALITY_IS(Property::CARDINALITY_IS_);

template <typename T>
inline void
reset_bits(T& bits) {
  bits = 0;
}

template <typename T>
inline void
reset_bit(T& bits, unsigned int bit) {
  bits &= ~(static_cast<T>(1) << bit);
}

template <typename T>
inline void
set_bit(T& bits, unsigned int bit, bool value) {
  if (value)
    bits |= static_cast<T>(1) << bit;
  else
    reset_bit(bits, bit);
}

template <typename T>
inline bool
get_bit(const T& bits, unsigned int bit) {
  return bits & (static_cast<T>(1) << bit);
}

template <typename T>
inline void
set_bits(T& bits, unsigned int start, unsigned int len, T value) {
  bits &= ~(((static_cast<T>(1) << len) - 1) << start);
  bits |= value << start;
}

template <typename T>
inline T
get_bits(T& bits, unsigned int start, unsigned int len) {
  return (bits >> start) & ((static_cast<T>(1) << len) - 1);
}

} // namespace Interval_NS

using namespace Interval_NS;
using namespace Boundary_NS;


template <typename Policy>
class Interval_Info_Null {
public:
  const_bool_nodef(may_be_empty, Policy::may_be_empty);
  const_bool_nodef(may_contain_infinity, Policy::may_contain_infinity);
  const_bool_nodef(check_empty_result, Policy::check_empty_result);
  const_bool_nodef(check_inexact, Policy::check_inexact);
  const_bool_nodef(store_special, false);
  const_bool_nodef(store_open, false);
  const_bool_nodef(cache_normalized, false);
  const_bool_nodef(cache_empty, false);
  const_bool_nodef(cache_singleton, false);
  void clear() {
  }
  void clear_boundary_properties(Boundary_Type) {
  }

  template <typename Property>
  void set_boundary_property(Boundary_Type, const Property&, typename Property::Value = Property::default_value) {
  }
  template <typename Property>
  typename Property::Value get_boundary_property(Boundary_Type, const Property&) const {
    return Property::unsupported_value;
  }
  template <typename Property>
  void set_interval_property(const Property&, typename Property::Value = Property::default_value) {
  }
  template <typename Property>
  typename Property::Value get_interval_property(const Property&) const {
    return Property::unsupported_value;
  }

  //! Swaps \p *this with \p y.
  void swap(Interval_Info_Null& y);

  void ascii_dump(std::ostream& s) const;
  bool ascii_load(std::istream& s);
};

template <typename Policy>
class Interval_Info_Null_Open : public Interval_Info_Null<Policy> {
public:
  const_bool_nodef(store_open, true);
  Interval_Info_Null_Open(bool o)
    : open(o) {
  }
  bool get_boundary_property(Boundary_Type, const Boundary_NS::Property& p) const {
    switch (p.type) {
    case Boundary_NS::Property::OPEN_:
      return open;
    default:
      return Boundary_NS::Property::unsupported_value;
    }
  }

  void ascii_dump(std::ostream& s) const;
  bool ascii_load(std::istream& s);

private:
  bool open;
};


template <typename T, typename Policy>
class Interval_Info_Bitset {
public:
  const_bool_nodef(may_be_empty, Policy::may_be_empty);
  const_bool_nodef(may_contain_infinity, Policy::may_contain_infinity);
  const_bool_nodef(check_empty_result, Policy::check_empty_result);
  const_bool_nodef(check_inexact, Policy::check_inexact);
  const_bool_nodef(store_special, Policy::store_special);
  const_bool_nodef(store_open, Policy::store_open);
  const_bool_nodef(cache_normalized, Policy::cache_normalized);
  const_bool_nodef(cache_empty, Policy::cache_empty);
  const_bool_nodef(cache_singleton, Policy::cache_singleton);
  const_int_nodef(lower_special_bit, Policy::next_bit);
  const_int_nodef(lower_open_bit, lower_special_bit + store_special);
  const_int_nodef(lower_normalized_bit, lower_open_bit + store_open);
  const_int_nodef(upper_special_bit, lower_normalized_bit + cache_normalized);
  const_int_nodef(upper_open_bit, upper_special_bit + store_special);
  const_int_nodef(upper_normalized_bit, upper_open_bit + store_open);
  const_int_nodef(cardinality_is_bit, upper_normalized_bit + cache_normalized);
  const_int_nodef(cardinality_0_bit, cardinality_is_bit + (cache_empty || cache_singleton));
  const_int_nodef(cardinality_1_bit, cardinality_0_bit + cache_empty);
  const_int_nodef(next_bit, cardinality_1_bit + cache_singleton);
  Interval_Info_Bitset() {
    // FIXME: would we have speed benefits with uninitialized info?
    // (Dirty_Temp)
    clear();
  }

  void clear() {
    reset_bits(bitset);
  }
  void clear_boundary_properties(Boundary_Type t) {
    set_boundary_property(t, SPECIAL, false);
    set_boundary_property(t, OPEN, false);
  }
  void set_boundary_property(Boundary_Type t, const Boundary_NS::Property& p, bool value = true) {
    switch (p.type) {
    case Boundary_NS::Property::SPECIAL_:
      if (store_special) {
	if (t == LOWER)
	  set_bit(bitset, lower_special_bit, value);
	else
	  set_bit(bitset, upper_special_bit, value);
      }
      break;
    case Boundary_NS::Property::OPEN_:
      if (store_open) {
	if (t == LOWER)
	  set_bit(bitset, lower_open_bit, value);
	else
	  set_bit(bitset, upper_open_bit, value);
      }
      break;
    case Boundary_NS::Property::NORMALIZED_:
      if (cache_normalized) {
	if (t == LOWER)
	  set_bit(bitset, lower_normalized_bit, value);
	else
	  set_bit(bitset, upper_normalized_bit, value);
      }
      break;
    default:
      break;
    }
  }
  bool get_boundary_property(Boundary_Type t, const Boundary_NS::Property& p) const {
    switch (p.type) {
    case Boundary_NS::Property::SPECIAL_:
      if (!store_special)
	return false;
      if (t == LOWER)
	return get_bit(bitset, lower_special_bit);
      else
	return get_bit(bitset, upper_special_bit);
    case Boundary_NS::Property::OPEN_:
      if (!store_open)
	return false;
      else if (t == LOWER)
	return get_bit(bitset, lower_open_bit);
      else
	return get_bit(bitset, upper_open_bit);
    case Boundary_NS::Property::NORMALIZED_:
      if (!cache_normalized)
	return false;
      else if (t == LOWER)
	return get_bit(bitset, lower_normalized_bit);
      else
	return get_bit(bitset, upper_normalized_bit);
    default:
      return false;
    }
  }
  void set_interval_property(const Interval_NS::Property& p, bool value = true) {
    switch (p.type) {
    case Interval_NS::Property::CARDINALITY_0_:
      if (cache_empty)
	set_bit(bitset, cardinality_0_bit, value);
      break;
    case Interval_NS::Property::CARDINALITY_1_:
      if (cache_singleton)
	set_bit(bitset, cardinality_1_bit, value);
      break;
    case Interval_NS::Property::CARDINALITY_IS_:
      if (cache_empty || cache_singleton)
	set_bit(bitset, cardinality_is_bit, value);
      break;
    default:
      break;
    }
  }
  bool get_interval_property(Interval_NS::Property p) const {
    switch (p.type) {
    case Interval_NS::Property::CARDINALITY_0_:
      return cache_empty && get_bit(bitset, cardinality_0_bit);
    case Interval_NS::Property::CARDINALITY_1_:
      return cache_singleton && get_bit(bitset, cardinality_1_bit);
    case Interval_NS::Property::CARDINALITY_IS_:
      return (cache_empty || cache_singleton) && get_bit(bitset, cardinality_is_bit);
    default:
      return false;
    }
  }

  //! Swaps \p *this with \p y.
  void swap(Interval_Info_Bitset& y);

  void ascii_dump(std::ostream& s) const;
  bool ascii_load(std::istream& s);

protected:
  T bitset;
};

}

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


#include <iomanip>

namespace Parma_Polyhedra_Library {

template <typename Policy>
inline void
Interval_Info_Null<Policy>::swap(Interval_Info_Null<Policy>&) {
}

template <typename Policy>
inline void
Interval_Info_Null<Policy>::ascii_dump(std::ostream& s) const {
}

template <typename Policy>
inline bool
Interval_Info_Null<Policy>::ascii_load(std::istream& s) {
  return true;
}

template <typename Policy>
inline void
Interval_Info_Null_Open<Policy>::ascii_dump(std::ostream& s) const {
  s << (open ? "open" : "closed");
}

template <typename Policy>
inline bool
Interval_Info_Null_Open<Policy>::ascii_load(std::istream& s) {
  std::string str;
  if (!(s >> str))
    return false;
  if (str == "open") {
    open = true;
    return true;
  }
  if (str == "closed") {
    open = false;
    return true;
  }
  return false;
}

template <typename T, typename Policy>
inline void
Interval_Info_Bitset<T, Policy>::swap(Interval_Info_Bitset<T, Policy>& y) {
  std::swap(bitset, y.bitset);
}

template <typename T, typename Policy>
inline void
Interval_Info_Bitset<T, Policy>::ascii_dump(std::ostream& s) const {
  std::ios_base::fmtflags old = s.flags();
  s << std::hex << bitset;
  s.flags(old);
}

template <typename T, typename Policy>
inline bool
Interval_Info_Bitset<T, Policy>::ascii_load(std::istream& s) {
  std::ios_base::fmtflags old = s.flags();
  if (s >> std::hex >> bitset) {
    s.flags(old);
    return s;
  }
  else
    return false;
}

} // namespace Parma_Polyhedra_Library

namespace std {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \relates Parma_Polyhedra_Library::Interval_Info_Null */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename Policy>
inline void
swap(Parma_Polyhedra_Library::Interval_Info_Null<Policy>& x,
     Parma_Polyhedra_Library::Interval_Info_Null<Policy>& y) {
  x.swap(y);
}

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \relates Parma_Polyhedra_Library::Interval_Info_Bitset */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename T, typename Policy>
inline void
swap(Parma_Polyhedra_Library::Interval_Info_Bitset<T, Policy>& x,
     Parma_Polyhedra_Library::Interval_Info_Bitset<T, Policy>& y) {
  x.swap(y);
}

} // namespace std

/* Automatically generated from PPL source file ../src/Interval_Info.defs.hh line 299. */

/* Automatically generated from PPL source file ../src/Interval.defs.hh line 31. */
#include <iosfwd>

// Temporary!
#include <iostream>

namespace Parma_Polyhedra_Library {

enum I_Result {
  I_EMPTY = 0,
  /*
  I_L_EQ = V_EQ,
  I_L_GT = V_GT,
  I_L_GE = V_GE,
  I_U_EQ = V_EQ << 6,
  I_U_LT = V_LT << 6,
  I_U_LE = V_LE << 6,
  */
  I_MAYBE_EMPTY = 1 << 12,
  I_SINGULARITIES = 1 << 13
};

enum Ternary { T_YES, T_NO, T_MAYBE };

inline I_Result
combine(Result l, Result u) {
  return static_cast<I_Result>(l | (u << 6));
}

inline Result
lower(I_Result r) {
  return static_cast<Result>(r & 63);
}

inline Result
upper(I_Result r) {
  return static_cast<Result>((r >> 6) & 63);
}

template <typename Info>
inline bool
unrepresentability_error(I_Result r, const Info&) {
  return !Info::store_special
    && (is_special(lower(r)) || is_special(upper(r)));
}

using namespace Boundary_NS;
using namespace Interval_NS;

struct Interval_Base {};

template <typename T, typename Enable = void>
struct Is_Singleton : public Is_Native_Or_Checked<T> {};

template <typename T>
struct Is_Interval : public Is_Same_Or_Derived<Interval_Base, T> {};

//! A generic, not necessarily closed, possibly restricted interval.
/*! \ingroup PPL_CXX_interface
  The class template type parameter \p Boundary represents the type
  of the interval boundaries, and can be chosen, among other possibilities,
  within one of the following number families:

  - a bounded precision native integer type (that is,
    from <CODE>signed char</CODE> to <CODE>long long</CODE>
    and from <CODE>int8_t</CODE> to <CODE>int64_t</CODE>);
  - a bounded precision floating point type (<CODE>float</CODE>,
    <CODE>double</CODE> or <CODE>long double</CODE>);
  - an unbounded integer or rational type, as provided by the C++ interface
    of GMP (<CODE>mpz_class</CODE> or <CODE>mpq_class</CODE>).

  The class template type parameter \p Info allows to control a number
  of features of the class, among which:

  - the ability to support open as well as closed boundaries;
  - the ability to represent empty intervals in addition to nonempty ones;
  - the ability to represent intervals of extended number families
    that contain positive and negative infinities;
  - the ability to support (independently from the type of the boundaries)
    plain intervals of real numbers and intervals subject to generic
    <EM>restrictions</EM> (e.g., intervals of integer numbers).
*/
template <typename Boundary, typename Info>
class Interval : public Interval_Base, private Info {
private:
  PPL_COMPILE_TIME_CHECK(!Info::store_special
                         || !std::numeric_limits<Boundary>::has_infinity,
                         "store_special is meaningless"
                         " when boundary type may contains infinity");
  Info& w_info() const {
    return const_cast<Interval&>(*this);
  }
  bool is_empty_nocache() const {
    return lt(UPPER, upper(), info(), LOWER, lower(), info());
  }
  bool is_singleton_nocache() const {
    return eq(LOWER, lower(), info(), UPPER, upper(), info());
  }
  Result lower_normalize() const {
    Result r;
    if (info().get_boundary_property(LOWER, NORMALIZED)
	|| info().get_boundary_property(LOWER, SPECIAL))
      r = V_EQ;
    else {
      Boundary& l = const_cast<Boundary&>(lower());
      if (info().get_boundary_property(LOWER, OPEN)) {
	r = info().restrict(round_dir_check(LOWER, true), l, V_GT);
	if (r != V_GT)
	  w_info().set_boundary_property(LOWER, OPEN, false);
      }
      else {
	r = info().restrict(round_dir_check(LOWER, true), l, V_GE);
	if (r == V_GT)
	  w_info().set_boundary_property(LOWER, OPEN);
      }
      w_info().set_boundary_property(LOWER, NORMALIZED);
    }
    return r;
  }
  Result upper_normalize() const {
    Result r;
    if (info().get_boundary_property(UPPER, NORMALIZED)
	|| info().get_boundary_property(UPPER, SPECIAL))
      r = V_EQ;
    else {
      Boundary& u = const_cast<Boundary&>(upper());
      if (info().get_boundary_property(UPPER, OPEN)) {
	r = info().restrict(round_dir_check(UPPER, true), u, V_LT);
	if (r != V_LT)
	  w_info().set_boundary_property(UPPER, OPEN, false);
      }
      else {
	r = info().restrict(round_dir_check(UPPER, true), u, V_LE);
	if (r == V_LT)
	  w_info().set_boundary_property(UPPER, OPEN);
      }
      w_info().set_boundary_property(UPPER, NORMALIZED);
    }
    return r;
  }


public:
  typedef Boundary boundary_type;
  typedef Info info_type;

  typedef Interval_NS::Property Property;

  void lower_load() {
#ifdef PPL_ABI_BREAKING_EXTRA_DEBUG
    lower_loaded = 1;
#endif
  }

  void upper_load() {
#ifdef PPL_ABI_BREAKING_EXTRA_DEBUG
    upper_loaded = 1;
#endif
  }

  void complete_init() {
#ifdef PPL_ABI_BREAKING_EXTRA_DEBUG
    assert(lower_loaded);
    assert(upper_loaded);
    completed = 1;
#endif
  }

  void complete_init_internal() {
#ifdef PPL_ABI_BREAKING_EXTRA_DEBUG
    lower_loaded = 1;
    upper_loaded = 1;
    completed = 1;
#endif
  }

  template <typename T>
  typename Enable_If<Is_Singleton<T>::value || Is_Interval<T>::value, Interval&>::type
  operator=(const T& x) {
    assign(x);
    return *this;
  }

  template <typename T>
  typename Enable_If<Is_Singleton<T>::value || Is_Interval<T>::value, Interval&>::type
  operator+=(const T& x) {
    add_assign(*this, x);
    return *this;
  }
  template <typename T>
  typename Enable_If<Is_Singleton<T>::value || Is_Interval<T>::value, Interval&>::type
  operator-=(const T& x) {
    sub_assign(*this, x);
    return *this;
  }
  template <typename T>
  typename Enable_If<Is_Singleton<T>::value || Is_Interval<T>::value, Interval&>::type
  operator*=(const T& x) {
    mul_assign(*this, x);
    return *this;
  }
  template <typename T>
  typename Enable_If<Is_Singleton<T>::value || Is_Interval<T>::value, Interval&>::type
  operator/=(const T& x) {
    div_assign(*this, x);
    return *this;
  }

  //! Swaps \p *this with \p y.
  void swap(Interval& y);

  Info& info() {
    return *this;
  }

  const Info& info() const {
    return *this;
  }

  Boundary& lower() {
    return lower_;
  }

  const Boundary& lower() const {
    return lower_;
  }

  Boundary& upper() {
    return upper_;
  }

  const Boundary& upper() const {
    return upper_;
  }

  Ternary is_empty_cached() const {
    if (info().get_interval_property(CARDINALITY_0))
      return info().get_interval_property(CARDINALITY_IS) ? T_YES : T_NO;
    else if (info().get_interval_property(CARDINALITY_IS))
      return T_NO;
    else
      return T_MAYBE;
  }

  Ternary is_singleton_cached() const {
    if (info().get_interval_property(CARDINALITY_1))
      return info().get_interval_property(CARDINALITY_IS) ? T_YES : T_NO;
    else if (info().get_interval_property(CARDINALITY_IS))
      return T_NO;
    else
      return T_MAYBE;
  }

  bool is_empty() const {
    switch (is_empty_cached()) {
    case T_NO:
      return false;
    case T_YES:
      return true;
    case T_MAYBE:
      bool r = is_empty_nocache();
      if (r) {
	w_info().set_interval_property(CARDINALITY_IS, r);
	w_info().set_interval_property(CARDINALITY_1, false);
      }
      w_info().set_interval_property(CARDINALITY_0);
      return r;
    }
    assert(false);
    return false;
  }

  bool is_singleton() const {
    switch (is_singleton_cached()) {
    case T_NO:
      return false;
    case T_YES:
      return true;
    case T_MAYBE:
      bool r = is_singleton_nocache();
      if (r) {
	w_info().set_interval_property(CARDINALITY_IS, r);
	w_info().set_interval_property(CARDINALITY_0, false);
      }
      w_info().set_interval_property(CARDINALITY_1);
      return r;
    }
    assert(false);
    return false;
  }

  bool has_restriction() const {
    return info().has_restriction();
  }

  I_Result normalize() const {
    assert(OK());
    if (has_restriction()) {
      Result rl = lower_normalize();
      Result ru = upper_normalize();
      // FIXME: this invalidation is not needed if interval is unchanged
      invalidate_cardinality_cache();
      info().normalize();
      assert(OK());
      return combine(rl, ru);
    }
    else
      return combine(V_EQ, V_EQ);
  }

  bool lower_is_open() const {
    assert(OK());
    return is_open(LOWER, lower(), info());
  }

  bool upper_is_open() const {
    assert(OK());
    return is_open(UPPER, upper(), info());
  }

  Result lower_shrink() {
    assert(OK());
    return shrink(LOWER, lower(), info(), false);
  }

  Result upper_shrink() {
    assert(OK());
    return shrink(UPPER, upper(), info(), false);
  }

  bool lower_is_unbounded() const {
    assert(OK());
    return Boundary_NS::is_unbounded(LOWER, lower(), info());
  }

  bool upper_is_unbounded() const {
    assert(OK());
    return Boundary_NS::is_unbounded(UPPER, upper(), info());
  }

  bool is_unbounded() const {
    assert(OK());
    return lower_is_unbounded() || upper_is_unbounded();
  }

  bool is_universe() const {
    assert(OK());
    return lower_is_unbounded() && upper_is_unbounded()
      && !has_restriction();
  }

  void invalidate_cardinality_cache() const {
    w_info().set_interval_property(CARDINALITY_IS, false);
    w_info().set_interval_property(CARDINALITY_0, false);
    w_info().set_interval_property(CARDINALITY_1, false);
  }

  template <typename T>
  Result lower_set_uninit(const T& x, bool open = false) {
    info().clear_boundary_properties(LOWER);
    Result rl = Boundary_NS::assign(LOWER, lower(), info(), LOWER, x, f_info(x, open));
    lower_load();
    return rl;
  }

  Result lower_set_uninit(const Unbounded&) {
    info().clear_boundary_properties(LOWER);
    Result rl = set_unbounded(LOWER, lower(), info());
    lower_load();
    return rl;
  }

  template <typename T>
  Result lower_set(const T& x, bool open = false) {
    assert(OK());
    info().clear_boundary_properties(LOWER);
    Result rl = Boundary_NS::assign(LOWER, lower(), info(), LOWER, x, f_info(x, open));
    invalidate_cardinality_cache();
    assert(OK());
    return rl;
  }

  Result lower_set(const Unbounded&) {
    assert(OK());
    info().clear_boundary_properties(LOWER);
    Result rl = set_unbounded(LOWER, lower(), info());
    invalidate_cardinality_cache();
    assert(OK());
    return rl;
  }

  template <typename T>
  Result lower_narrow(const T& x, bool open = false) {
    assert(OK());
    if (ge(LOWER, lower(), info(), LOWER, x, f_info(x, open)))
      return V_EQ;
    return lower_set(x, open);
  }

  template <typename T>
  Result lower_widen(const T& x, bool open = false) {
    assert(OK());
    if (le(LOWER, lower(), info(), LOWER, x, f_info(x, open)))
      return V_EQ;
    return lower_set(x, open);
  }

  Result lower_widen(const Unbounded&) {
    assert(OK());
    if (lower_is_unbounded())
      return V_EQ;
    info().clear_boundary_properties(LOWER);
    Result rl = set_unbounded(LOWER, lower(), info());
    invalidate_cardinality_cache();
    assert(OK());
    return V_EQ;
  }

  template <typename T>
  Result upper_set_uninit(const T& x, bool open = false) {
    info().clear_boundary_properties(UPPER);
    Result rl = Boundary_NS::assign(UPPER, upper(), info(), UPPER, x, f_info(x, open));
    upper_load();
    return rl;
  }
  Result upper_set_uninit(const Unbounded&) {
    info().clear_boundary_properties(UPPER);
    Result rl = set_unbounded(UPPER, upper(), info());
    upper_load();
    return rl;
  }

  template <typename T>
  Result upper_set(const T& x, bool open = false) {
    assert(OK());
    info().clear_boundary_properties(UPPER);
    Result rl = Boundary_NS::assign(UPPER, upper(), info(), UPPER, x, f_info(x, open));
    invalidate_cardinality_cache();
    assert(OK());
    return rl;
  }

  Result upper_set(const Unbounded&) {
    assert(OK());
    info().clear_boundary_properties(UPPER);
    Result rl = set_unbounded(UPPER, upper(), info());
    invalidate_cardinality_cache();
    assert(OK());
    return rl;
  }

  template <typename T>
  Result upper_narrow(const T& x, bool open = false) {
    assert(OK());
    if (le(UPPER, upper(), info(), UPPER, x, f_info(x, open)))
      return V_EQ;
    return upper_set(x, open);
  }

  template <typename T>
  Result upper_widen(const T& x, bool open = false) {
    assert(OK());
    if (ge(UPPER, upper(), info(), UPPER, x, f_info(x, open)))
      return V_EQ;
    return upper_set(x, open);
  }

  Result upper_widen(const Unbounded&) {
    assert(OK());
    if (upper_is_unbounded())
      return V_EQ;
    info().clear_boundary_properties(UPPER);
    Result rl = set_unbounded(UPPER, upper(), info());
    invalidate_cardinality_cache();
    assert(OK());
    return rl;
  }

  I_Result assign(Degenerate_Element e) {
    I_Result r;
    Result rl, ru;
    info().clear();
    switch (e) {
    case EMPTY:
      info().set_interval_property(CARDINALITY_IS);
      info().set_interval_property(CARDINALITY_0);
      lower_set_uninit(1);
      upper_set_uninit(0);
      r = I_EMPTY;
      break;
    case UNIVERSE:
      info().set_interval_property(CARDINALITY_0, true);
      info().set_interval_property(CARDINALITY_1, true);
      rl = lower_set_uninit(UNBOUNDED);
      ru = upper_set_uninit(UNBOUNDED);
      r = combine(rl, ru);
      break;
    default:
      assert(0);
      r = I_EMPTY;
      break;
    }
    complete_init();
    assert(OK());
    return r;
  }

  template <typename From>
  typename Enable_If<Is_Special<From>::value, I_Result>::type
  assign(const From&) {
    info().clear();
    info().set_interval_property(CARDINALITY_0, true);
    info().set_interval_property(CARDINALITY_1, true);
    Result rl, ru;
    switch (From::code) {
    case VC_MINUS_INFINITY:
      rl = Boundary_NS::set_minus_infinity(LOWER, lower(), info());
      ru = Boundary_NS::set_minus_infinity(UPPER, upper(), info());
      break;
    case VC_PLUS_INFINITY:
      rl = Boundary_NS::set_plus_infinity(LOWER, lower(), info());
      ru = Boundary_NS::set_plus_infinity(UPPER, upper(), info());
      break;
    default:
      assert(0);
      rl = VC_NAN;
      ru = VC_NAN;
    }
    complete_init_internal();
    assert(OK());
    return combine(rl, ru);
  }

  I_Result set_infinities() {
    info().clear();
    info().set_interval_property(CARDINALITY_0, true);
    info().set_interval_property(CARDINALITY_1, true);
    // FIXME: what about restrictions?
    Result rl = Boundary_NS::set_minus_infinity(LOWER, lower(), info());
    Result ru = Boundary_NS::set_plus_infinity(UPPER, upper(), info());
    complete_init_internal();
    assert(OK());
    return combine(rl, ru);
  }

  bool is_topologically_closed() const {
    assert(OK());
    return !Info::store_open
      || is_empty()
      || ((lower_is_unbounded() || !lower_is_open())
          && (upper_is_unbounded() || !upper_is_open()));
  }

  //! Assigns to \p *this its topological closure.
  void topological_closure_assign() {
    if (!Info::store_open || is_empty())
      return;

    if (!lower_is_unbounded())
      info().set_boundary_property(LOWER, OPEN, false);

    if (!upper_is_unbounded())
      info().set_boundary_property(UPPER, OPEN, false);
  }

  bool is_infinity() const {
    assert(OK());
    if (is_reverse_infinity(LOWER, lower(), info()))
      return 1;
    else if (is_reverse_infinity(UPPER, upper(), info()))
      return -1;
    else
      return 0;
  }

  bool contains_integer_point() const {
    assert(OK());
    if (is_empty())
      return false;
    if (is_unbounded())
      return true;
    Boundary l;
    if (lower_is_open()) {
      add_assign_r(l, lower(), Boundary(1), ROUND_DOWN);
      floor_assign_r(l, l, ROUND_DOWN);
    }
    else
      ceil_assign_r(l, lower(), ROUND_DOWN);
    Boundary u;
    if (upper_is_open()) {
      sub_assign_r(u, upper(), Boundary(1), ROUND_UP);
      ceil_assign_r(u, u, ROUND_UP);
    }
    else
      floor_assign_r(u, upper(), ROUND_UP);
    return u >= l;
  }

  //! 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;

  void ascii_dump(std::ostream& s) const;
  bool ascii_load(std::istream& s);

  bool OK() const {
#ifdef PPL_ABI_BREAKING_EXTRA_DEBUG
    if (!completed) {
	std::cerr << "The interval initialization has not been completed."
                  << std::endl;
	return false;
    }
#endif
#if 0
    if (!Info::may_be_empty && is_empty()) {
#ifndef NDEBUG
	std::cerr << "The interval is unexpectedly empty.\n";
#endif
	return false;
    }
#endif

    if (is_open(LOWER, lower(), info())) {
      if (is_plus_infinity(LOWER, lower(), info())) {
#ifndef NDEBUG
	std::cerr << "The lower boundary is +inf open.\n";
#endif
      }
    }
    else if (!Info::may_contain_infinity
	     && (is_minus_infinity(LOWER, lower(), info())
		 || is_plus_infinity(LOWER, lower(), info()))) {
#ifndef NDEBUG
      std::cerr << "The lower boundary is unexpectedly infinity.\n";
#endif
      return false;
    }
    if (!info().get_boundary_property(LOWER, SPECIAL)) {
      if (is_not_a_number(lower())) {
#ifndef NDEBUG
	std::cerr << "The lower boundary is not a number.\n";
#endif
	return false;
      }
#if 0
      if (info().get_boundary_property(LOWER, NORMALIZED)
	  && !info().is_restricted(lower())) {
#ifndef NDEBUG
	std::cerr << "The lower boundary is marked to be normalized, "
                  << "but it is not.\n";
#endif
	return false;
      }
#endif
    }

    if (is_open(UPPER, upper(), info())) {
      if (is_minus_infinity(UPPER, upper(), info())) {
#ifndef NDEBUG
	std::cerr << "The upper boundary is -inf open.\n";
#endif
      }
    }
    else if (!Info::may_contain_infinity
	     && (is_minus_infinity(UPPER, upper(), info())
		 || is_plus_infinity(UPPER, upper(), info()))) {
#ifndef NDEBUG
      std::cerr << "The upper boundary is unexpectedly infinity."
                << std::endl;
#endif
      return false;
    }
    if (!info().get_boundary_property(UPPER, SPECIAL)) {
      if (is_not_a_number(upper())) {
#ifndef NDEBUG
	std::cerr << "The upper boundary is not a number.\n";
#endif
	return false;
      }
#if 0
      if (info().get_boundary_property(UPPER, NORMALIZED)
	  && !info().is_restricted(upper())) {
#ifndef NDEBUG
	std::cerr << "The upper boundary is marked to be normalized, "
                  << "but it is not.\n";
#endif
	return false;
      }
#endif
    }

    Ternary t;

    t = is_empty_cached();
    if (t == T_YES) {
      if (!is_empty_nocache()) {
#ifndef NDEBUG
	std::cerr << "The interval is marked to be empty, "
                  << "but actually it is not empty.\n";
#endif
	return false;
      }
    }
    else if (t == T_NO) {
      if (is_empty_nocache()) {
#ifndef NDEBUG
	std::cerr << "The interval is marked to be not empty, "
                  << "but actually it is empty.\n";
#endif
	return false;
      }
    }

    t = is_singleton_cached();
    if (t == T_YES) {
      if (!is_singleton_nocache()) {
#ifndef NDEBUG
	std::cerr << "The interval is marked to be singleton, "
                  << "but actually it is not singleton.\n";
#endif
	return false;
      }
    }
    else if (t == T_NO) {
      if (is_singleton_nocache()) {
#ifndef NDEBUG
	std::cerr << "The interval is marked to be not singleton, "
                  << "but actually it is singleton.\n";
#endif
	return false;
      }
    }

    if (info().get_interval_property(CARDINALITY_IS) &&
	info().get_interval_property(CARDINALITY_0)
        == info().get_interval_property(CARDINALITY_1)) {
#ifndef NDEBUG
      std::cerr << "The interval is marked to know its cardinality, "
                << "but this is unspecified or ambiguous.\n";
#endif
      return false;
    }

    // Everything OK.
    return true;
  }

  Interval()
#ifdef PPL_ABI_BREAKING_EXTRA_DEBUG
    : lower_loaded(0), upper_loaded(0), completed(0)
#endif
  {
  }

  template <typename T>
  explicit Interval(const T& x)
#ifdef PPL_ABI_BREAKING_EXTRA_DEBUG
    : lower_loaded(0), upper_loaded(0), completed(0)
#endif
  {
    assign(x);
  }

  template <typename T>
  typename Enable_If<Is_Singleton<T>::value
                     || Is_Interval<T>::value, bool>::type
  contains(const T& y) const;

  template <typename T>
  typename Enable_If<Is_Singleton<T>::value
                     || Is_Interval<T>::value, bool>::type
  strictly_contains(const T& y) const;

  template <typename T>
  typename Enable_If<Is_Singleton<T>::value
                     || Is_Interval<T>::value, bool>::type
  is_disjoint_from(const T& y) const;

  template <typename From1, typename From2>
  I_Result assign(const From1& l, const From2& u);

  template <typename From>
  typename Enable_If<Is_Singleton<From>::value
                     || Is_Interval<From>::value, I_Result>::type
  assign(const From& x);

  template <typename Type>
  typename Enable_If<Is_Singleton<Type>::value
                     || Is_Interval<Type>::value, bool>::type
  can_be_exactly_joined_to(const Type& x) const;

  template <typename From>
  typename Enable_If<Is_Singleton<From>::value
                     || Is_Interval<From>::value, I_Result>::type
  join_assign(const From& x);

  template <typename From1, typename From2>
  typename Enable_If<((Is_Singleton<From1>::value
                       || Is_Interval<From1>::value)
		      && (Is_Singleton<From2>::value
                          || Is_Interval<From2>::value)), I_Result>::type
  join_assign(const From1& x, const From2& y);

  template <typename From>
  typename Enable_If<Is_Singleton<From>::value
                     || Is_Interval<From>::value, I_Result>::type
  intersect_assign(const From& x);

  template <typename From1, typename From2>
  typename Enable_If<((Is_Singleton<From1>::value
                       || Is_Interval<From1>::value)
		      && (Is_Singleton<From2>::value
                          || Is_Interval<From2>::value)), I_Result>::type
  intersect_assign(const From1& x, const From2& y);

  /*! \brief
    Assigns to \p *this the smallest interval containing the set-theoretic
    difference of \p *this and \p x.
  */
  template <typename From>
  typename Enable_If<Is_Singleton<From>::value
                     || Is_Interval<From>::value, I_Result>::type
  difference_assign(const From& x);

  /*! \brief
    Assigns to \p *this the smallest interval containing the set-theoretic
    difference of \p x and \p y.
  */
  template <typename From1, typename From2>
  typename Enable_If<((Is_Singleton<From1>::value
                       || Is_Interval<From1>::value)
		      && (Is_Singleton<From2>::value
                          || Is_Interval<From2>::value)), I_Result>::type
  difference_assign(const From1& x, const From2& y);

  /*! \brief
    Assigns to \p *this the largest interval contained in the set-theoretic
    difference of \p *this and \p x.
  */
  template <typename From>
  typename Enable_If<Is_Singleton<From>::value
                     || Is_Interval<From>::value, I_Result>::type
  lower_approximation_difference_assign(const From& x);

  /*! \brief
    Assigns to \p *this a \ref Meet_Preserving_Simplification
    "meet-preserving simplification" of \p *this with respect to \p y.

    \return
    \c false if and only if the meet of \p *this and \p y is empty.
  */
  template <typename From>
  typename Enable_If<Is_Interval<From>::value, bool>::type
  simplify_using_context_assign(const From& y);

  /*! \brief
    Assigns to \p *this an interval having empty intersection with \p y.
    The assigned interval should be as large as possible.

    \note
    Depending on interval restrictions, there could be many
    maximal intervals all inconsistent with respect to \p y.
  */
  template <typename From>
  typename Enable_If<Is_Interval<From>::value, void>::type
  empty_intersection_assign(const From& y);

  /*! \brief
    Refines \p to according to the existential relation \p rel with \p x.

    The \p to interval is restricted to become, upon successful exit,
    the smallest interval of its type that contains the set
    \f[
      \{\,
        a \in \mathtt{to}
      \mid
        \exists b \in \mathtt{x} \st a \mathrel{\mathtt{rel}} b
      \,\}.
    \f]
    \return
    ???
  */
  template <typename From>
  typename Enable_If<Is_Singleton<From>::value
                     || Is_Interval<From>::value, I_Result>::type
  refine_existential(Relation_Symbol rel, const From& x);

  /*! \brief
    Refines \p to so that it satisfies the universal relation \p rel with \p x.

    The \p to interval is restricted to become, upon successful exit,
    the smallest interval of its type that contains the set
    \f[
      \{\,
        a \in \mathtt{to}
      \mid
        \forall b \in \mathtt{x} \itc a \mathrel{\mathtt{rel}} b
      \,\}.
    \f]
    \return
    ???
  */
  template <typename From>
  typename Enable_If<Is_Singleton<From>::value
                     || Is_Interval<From>::value, I_Result>::type
  refine_universal(Relation_Symbol rel, const From& x);

  template <typename From>
  typename Enable_If<Is_Singleton<From>::value
                     || Is_Interval<From>::value, I_Result>::type
  neg_assign(const From& x);

  template <typename From1, typename From2>
  typename Enable_If<((Is_Singleton<From1>::value || Is_Interval<From1>::value)
		      && (Is_Singleton<From2>::value || Is_Interval<From2>::value)), I_Result>::type
  add_assign(const From1& x, const From2& y);

  template <typename From1, typename From2>
  typename Enable_If<((Is_Singleton<From1>::value || Is_Interval<From1>::value)
		      && (Is_Singleton<From2>::value || Is_Interval<From2>::value)), I_Result>::type
  sub_assign(const From1& x, const From2& y);

  template <typename From1, typename From2>
  typename Enable_If<((Is_Singleton<From1>::value || Is_Interval<From1>::value)
		      && (Is_Singleton<From2>::value || Is_Interval<From2>::value)), I_Result>::type
  mul_assign(const From1& x, const From2& y);

  template <typename From1, typename From2>
  typename Enable_If<((Is_Singleton<From1>::value || Is_Interval<From1>::value)
		      && (Is_Singleton<From2>::value || Is_Interval<From2>::value)), I_Result>::type
  div_assign(const From1& x, const From2& y);

  template <typename From, typename Iterator>
  typename Enable_If<Is_Interval<From>::value, void>::type
  CC76_widening_assign(const From& y, Iterator first, Iterator last);

private:
  Boundary lower_;
  Boundary upper_;
#ifdef PPL_ABI_BREAKING_EXTRA_DEBUG
  unsigned int lower_loaded:1;
  unsigned int upper_loaded:1;
  unsigned int completed:1;
#endif
};

} // namespace Parma_Polyhedra_Library

/* Automatically generated from PPL source file ../src/Interval.inlines.hh line 1. */
/* Inline functions for the Interval class and its constituents.
*/


namespace Parma_Polyhedra_Library {

template <typename Boundary, typename Info>
inline memory_size_type
Interval<Boundary, Info>::external_memory_in_bytes() const {
  return Parma_Polyhedra_Library::external_memory_in_bytes(lower())
    + Parma_Polyhedra_Library::external_memory_in_bytes(upper());
}

template <typename Boundary, typename Info>
inline memory_size_type
Interval<Boundary, Info>::total_memory_in_bytes() const {
  return sizeof(*this) + external_memory_in_bytes();
}

template <typename Boundary, typename Info>
inline void
Interval<Boundary, Info>::swap(Interval<Boundary, Info>& y) {
  std::swap(lower(), y.lower());
  std::swap(upper(), y.upper());
  std::swap(info(), y.info());
}

template <typename Boundary, typename Info>
inline bool
f_is_empty(const Interval<Boundary, Info>& x) {
  return x.is_empty();
}
template <typename Boundary, typename Info>
inline bool
f_is_singleton(const Interval<Boundary, Info>& x) {
  return x.is_singleton();
}
template <typename Boundary, typename Info>
inline int
is_infinity(const Interval<Boundary, Info>& x) {
  return x.is_infinity();
}

namespace Interval_NS {

template <typename Boundary, typename Info>
inline const Boundary&
f_lower(const Interval<Boundary, Info>& x) {
  return x.lower();
}
template <typename Boundary, typename Info>
inline const Boundary&
f_upper(const Interval<Boundary, Info>& x) {
  return x.upper();
}
template <typename Boundary, typename Info>
inline const Info&
f_info(const Interval<Boundary, Info>& x) {
  return x.info();
}

struct Scalar_As_Interval_Policy {
  const_bool_nodef(may_be_empty, true);
  const_bool_nodef(may_contain_infinity, true);
  const_bool_nodef(check_empty_result, false);
  const_bool_nodef(check_inexact, false);
};

typedef Interval_Restriction_None<Interval_Info_Null<Scalar_As_Interval_Policy> > Scalar_As_Interval_Info;

const Scalar_As_Interval_Info SCALAR_INFO;

typedef Interval_Restriction_None<Interval_Info_Null_Open<Scalar_As_Interval_Policy> > Scalar_As_Interval_Info_Open;

template <typename T>
inline typename Enable_If<Is_Singleton<T>::value, const T&>::type
f_lower(const T& x) {
  return x;
}
template <typename T>
inline typename Enable_If<Is_Singleton<T>::value, const T&>::type
f_upper(const T& x) {
  return x;
}
template <typename T>
inline typename Enable_If<Is_Singleton<T>::value, const Scalar_As_Interval_Info&>::type
f_info(const T&) {
  return SCALAR_INFO;
}
template <typename T>
inline typename Enable_If<Is_Singleton<T>::value, Scalar_As_Interval_Info_Open>::type
f_info(const T&, bool open) {
  return Scalar_As_Interval_Info_Open(open);
}

template <typename T>
inline typename Enable_If<Is_Singleton<T>::value, bool>::type
f_is_empty(const T& x) {
  return is_not_a_number(x);
}

template <typename T>
inline typename Enable_If<Is_Singleton<T>::value, bool>::type
f_is_singleton(const T& x) {
  return !f_is_empty(x);
}

template <typename T>
inline typename Enable_If<Is_Singleton<T>::value || Is_Interval<T>::value, Ternary>::type
f_is_empty_lazy(const T& x) {
  if (f_info(x).get_interval_property(CARDINALITY_0))
    return f_info(x).get_interval_property(CARDINALITY_IS) ? T_YES : T_NO;
  else
    return T_MAYBE;
}

} // namespace Interval_NS

template <typename T>
inline typename Enable_If<Is_Singleton<T>::value || Is_Interval<T>::value, bool>::type
is_singleton_integer(const T& x) {
  return is_singleton(x) && is_integer(f_lower(x));
}

template <typename T>
inline typename Enable_If<Is_Singleton<T>::value || Is_Interval<T>::value, bool>::type
check_empty_arg(const T& x) {
  if (f_info(x).may_be_empty)
    return f_is_empty(x);
  else {
    assert(!f_is_empty(x));
    return false;
  }
}

template <typename Boundary, typename Info>
inline I_Result
check_empty_result(const Interval<Boundary, Info>& x, I_Result r) {
  if (Info::check_empty_result && f_is_empty(x))
    return I_EMPTY;
  else
    return static_cast<I_Result>(r | I_MAYBE_EMPTY);
}

template <typename T1, typename T2>
inline typename Enable_If<((Is_Singleton<T1>::value || Is_Interval<T1>::value)
			   && (Is_Singleton<T2>::value || Is_Interval<T2>::value)
			   && (Is_Interval<T1>::value || Is_Interval<T2>::value)),
			  bool>::type
operator==(const T1& x, const T2& y) {
  assert(f_OK(x));
  assert(f_OK(y));
  if (check_empty_arg(x))
    return check_empty_arg(y);
  else if (check_empty_arg(y))
    return false;
  // FIXME: the two restrictions should be evaluated in the context of
  // the specific interval
  return eq_restriction(f_info(x), f_info(y))
    && eq(LOWER, f_lower(x), f_info(x), LOWER, f_lower(y), f_info(y))
    && eq(UPPER, f_upper(x), f_info(x), UPPER, f_upper(y), f_info(y));
}

template <typename T1, typename T2>
inline typename Enable_If<((Is_Singleton<T1>::value || Is_Interval<T1>::value)
			   && (Is_Singleton<T2>::value || Is_Interval<T2>::value)
			   && (Is_Interval<T1>::value || Is_Interval<T2>::value)),
			  bool>::type
operator!=(const T1& x, const T2& y) {
  return !(x == y);
}

template <typename Boundary, typename Info>
template <typename T>
inline typename Enable_If<Is_Singleton<T>::value || Is_Interval<T>::value, bool>::type
Interval<Boundary, Info>::contains(const T& y) const {
  assert(OK());
  assert(f_OK(y));
  if (check_empty_arg(y))
    return true;
  if (check_empty_arg(*this))
    return false;
  // FIXME: the two restrictions should be evaluated in the context of
  // the specific interval
  if (!contains_restriction(info(), f_info(y)))
      return false;
  return le(LOWER, lower(), info(), LOWER, f_lower(y), f_info(y))
    && ge(UPPER, upper(), info(), UPPER, f_upper(y), f_info(y));
}

template <typename Boundary, typename Info>
template <typename T>
inline typename Enable_If<Is_Singleton<T>::value || Is_Interval<T>::value, bool>::type
Interval<Boundary, Info>::strictly_contains(const T& y) const {
  assert(OK());
  assert(f_OK(y));
  if (check_empty_arg(y))
    return !check_empty_arg(*this);
  if (check_empty_arg(*this))
    return false;
  // FIXME: the two restrictions should be evaluated in the context of
  // the specific interval
  if (!contains_restriction(info(), f_info(y)))
      return false;
  else if (!eq_restriction(info(), f_info(y)))
    return le(LOWER, lower(), info(), LOWER, f_lower(y), f_info(y))
      && ge(UPPER, upper(), info(), UPPER, f_upper(y), f_info(y));
  return (lt(LOWER, lower(), info(), LOWER, f_lower(y), f_info(y))
	  && ge(UPPER, upper(), info(), UPPER, f_upper(y), f_info(y)))
    || (le(LOWER, lower(), info(), LOWER, f_lower(y), f_info(y))
	&& gt(UPPER, upper(), info(), UPPER, f_upper(y), f_info(y)));
}

template <typename Boundary, typename Info>
template <typename T>
inline typename Enable_If<Is_Singleton<T>::value
                          || Is_Interval<T>::value, bool>::type
Interval<Boundary, Info>::is_disjoint_from(const T& y) const {
  assert(OK());
  assert(f_OK(y));
  if (check_empty_arg(*this) || check_empty_arg(y))
    return true;
//   CHECKME.
//   if (!contains_restriction(info(), f_info(y)))
//       return false;
  return gt(LOWER, lower(), info(), UPPER, f_upper(y), f_info(y))
    || lt(UPPER, upper(), info(), LOWER, f_lower(y), f_info(y));
}

template <typename To_Boundary, typename To_Info>
template <typename From1, typename From2>
inline I_Result
Interval<To_Boundary, To_Info>::assign(const From1& l, const From2& u) {
  info().clear();
  Result rl = Boundary_NS::assign(LOWER, lower(), info(), LOWER, l, f_info(l));
  Result ru = Boundary_NS::assign(UPPER, upper(), info(), UPPER, u, f_info(u));
  complete_init_internal();
  assert(OK());
  // The following Parma_Polyhedra_Library:: qualification is to work
  // around a bug in version 10.0 of the Intel C/C++ compiler.
  return Parma_Polyhedra_Library::check_empty_result(*this, combine(rl, ru));
}

template <typename To_Boundary, typename To_Info>
template <typename From>
inline typename Enable_If<Is_Singleton<From>::value
                          || Is_Interval<From>::value, I_Result>::type
Interval<To_Boundary, To_Info>::assign(const From& x) {
  assert(f_OK(x));
  if (check_empty_arg(x))
    return assign(EMPTY);
  PPL_DIRTY_TEMP(To_Info, to_info);
  to_info.clear();
  if (!assign_restriction(to_info, x))
    return assign(EMPTY);
  Result rl = Boundary_NS::assign(LOWER, lower(), to_info,
				  LOWER, f_lower(x), f_info(x));
  Result ru = Boundary_NS::assign(UPPER, upper(), to_info,
				  UPPER, f_upper(x), f_info(x));
  assign_or_swap(info(), to_info);
  complete_init_internal();
  assert(OK());
  return combine(rl, ru);
}

template <typename To_Boundary, typename To_Info>
template <typename From>
inline typename Enable_If<Is_Singleton<From>::value
                          || Is_Interval<From>::value, I_Result>::type
Interval<To_Boundary, To_Info>::join_assign(const From& x) {
  assert(f_OK(x));
  if (check_empty_arg(*this))
    return assign(x);
  if (check_empty_arg(x))
    return combine(V_EQ, V_EQ);
  if (!join_restriction(info(), *this, x))
    return assign(EMPTY);
  info().set_interval_property(CARDINALITY_IS, false);
  info().set_interval_property(CARDINALITY_0);
  info().set_interval_property(CARDINALITY_1, false);
  Result rl, ru;
  rl = min_assign(LOWER, lower(), info(), LOWER, f_lower(x), f_info(x));
  ru = max_assign(UPPER, upper(), info(), UPPER, f_upper(x), f_info(x));
  assert(OK());
  return combine(rl, ru);
}

template <typename To_Boundary, typename To_Info>
template <typename From1, typename From2>
inline typename Enable_If<((Is_Singleton<From1>::value
                            || Is_Interval<From1>::value)
			   && (Is_Singleton<From2>::value
                               || Is_Interval<From2>::value)), I_Result>::type
Interval<To_Boundary, To_Info>::join_assign(const From1& x, const From2& y) {
  assert(f_OK(x));
  assert(f_OK(y));
  if (check_empty_arg(x))
    return assign(y);
  if (check_empty_arg(y))
    return assign(x);
  PPL_DIRTY_TEMP(To_Info, to_info);
  to_info.clear();
  if (!join_restriction(to_info, x, y))
    return assign(EMPTY);
  to_info.set_interval_property(CARDINALITY_0);
  Result rl, ru;
  rl = min_assign(LOWER, lower(), to_info,
		  LOWER, f_lower(x), f_info(x),
		  LOWER, f_lower(y), f_info(y));
  ru = max_assign(UPPER, upper(), to_info,
		  UPPER, f_upper(x), f_info(x),
		  UPPER, f_upper(y), f_info(y));
  assign_or_swap(info(), to_info);
  complete_init_internal();
  assert(OK());
  return combine(rl, ru);
}

template <typename Boundary, typename Info>
template <typename Type>
inline typename Enable_If<Is_Singleton<Type>::value
                          || Is_Interval<Type>::value, bool>::type
Interval<Boundary, Info>::can_be_exactly_joined_to(const Type& x) const {
  // FIXME: the two restrictions should be evaluated in the context of
  // the specific interval
  if (!eq_restriction(info(), f_info(x)))
    return false;
  PPL_DIRTY_TEMP(Boundary, b);
  if (gt(LOWER, lower(), info(), UPPER, f_upper(x), f_info(x))) {
    b = lower();
    return info().restrict(round_dir_check(LOWER, true), b, V_LT) == V_EQ &&
      eq(LOWER, b, info(), UPPER, f_upper(x), f_info(x));
  }
  else if (lt(UPPER, upper(), info(), LOWER, f_lower(x), f_info(x))) {
    b = upper();
    return info().restrict(round_dir_check(UPPER, true), b, V_GT) == V_EQ &&
      eq(UPPER, b, info(), LOWER, f_lower(x), f_info(x));
  }
  return true;
}


template <typename To_Boundary, typename To_Info>
template <typename From>
inline typename Enable_If<Is_Singleton<From>::value
                          || Is_Interval<From>::value, I_Result>::type
Interval<To_Boundary, To_Info>::intersect_assign(const From& x) {
  assert(f_OK(x));
  if (!intersect_restriction(info(), *this, x))
    return assign(EMPTY);
  // FIXME: more accurate?
  invalidate_cardinality_cache();
  Result rl, ru;
  rl = max_assign(LOWER, lower(), info(), LOWER, f_lower(x), f_info(x));
  ru = min_assign(UPPER, upper(), info(), UPPER, f_upper(x), f_info(x));
  assert(OK());
  // The following Parma_Polyhedra_Library:: qualification is to work
  // around a bug in version 10.0 of the Intel C/C++ compiler.
  return Parma_Polyhedra_Library::check_empty_result(*this, combine(rl, ru));
}

template <typename To_Boundary, typename To_Info>
template <typename From1, typename From2>
inline typename Enable_If<((Is_Singleton<From1>::value
                            || Is_Interval<From1>::value)
			   && (Is_Singleton<From2>::value
                               || Is_Interval<From2>::value)), I_Result>::type
Interval<To_Boundary, To_Info>::intersect_assign(const From1& x,
                                                 const From2& y) {
  assert(f_OK(x));
  assert(f_OK(y));
  PPL_DIRTY_TEMP(To_Info, to_info);
  to_info.clear();
  if (!intersect_restriction(to_info, x, y))
    return assign(EMPTY);
  Result rl, ru;
  rl = max_assign(LOWER, lower(), to_info,
		  LOWER, f_lower(x), f_info(x),
		  LOWER, f_lower(y), f_info(y));
  ru = min_assign(UPPER, upper(), to_info,
		  UPPER, f_upper(x), f_info(x),
		  UPPER, f_upper(y), f_info(y));
  assign_or_swap(info(), to_info);
  complete_init_internal();
  assert(OK());
  // The following Parma_Polyhedra_Library:: qualification is to work
  // around a bug in version 10.0 of the Intel C/C++ compiler.
  return Parma_Polyhedra_Library::check_empty_result(*this, combine(rl, ru));
}

template <typename To_Boundary, typename To_Info>
template <typename From>
inline typename Enable_If<Is_Singleton<From>::value
                          || Is_Interval<From>::value, I_Result>::type
Interval<To_Boundary, To_Info>::difference_assign(const From& x) {
  assert(f_OK(x));
  // FIXME: restrictions
  if (lt(UPPER, upper(), info(), LOWER, f_lower(x), f_info(x)) ||
      gt(LOWER, lower(), info(), UPPER, f_upper(x), f_info(x)))
    return combine(V_EQ, V_EQ);
  bool nl = ge(LOWER, lower(), info(), LOWER, f_lower(x), f_info(x));
  bool nu = le(UPPER, upper(), info(), UPPER, f_upper(x), f_info(x));
  Result rl = V_EQ, ru = V_EQ;
  if (nl) {
    if (nu)
      return assign(EMPTY);
    else {
      invalidate_cardinality_cache();
      info().clear_boundary_properties(LOWER);
      rl = complement(LOWER, lower(), info(), UPPER, f_upper(x), f_info(x));
    }
  }
  else if (nu) {
    invalidate_cardinality_cache();
    info().clear_boundary_properties(UPPER);
    ru = complement(UPPER, upper(), info(), LOWER, f_lower(x), f_info(x));
  }
  assert(OK());
  return combine(rl, ru);
}

template <typename To_Boundary, typename To_Info>
template <typename From1, typename From2>
inline typename Enable_If<((Is_Singleton<From1>::value
                            || Is_Interval<From1>::value)
			   && (Is_Singleton<From2>::value
                               || Is_Interval<From2>::value)), I_Result>::type
Interval<To_Boundary, To_Info>::difference_assign(const From1& x,
                                                  const From2& y) {
  assert(f_OK(x));
  assert(f_OK(y));
  PPL_DIRTY_TEMP(To_Info, to_info);
  to_info.clear();
  // FIXME: restrictions
  if (lt(UPPER, f_upper(x), f_info(x), LOWER, f_lower(y), f_info(y)) ||
      gt(LOWER, f_lower(x), f_info(x), UPPER, f_upper(y), f_info(y)))
    return assign(x);
  bool nl = ge(LOWER, f_lower(x), f_info(x), LOWER, f_lower(y), f_info(y));
  bool nu = le(UPPER, f_upper(x), f_info(x), UPPER, f_upper(y), f_info(y));
  Result rl = V_EQ, ru = V_EQ;
  if (nl) {
    if (nu)
      return assign(EMPTY);
    else {
      rl = complement(LOWER, lower(), info(), UPPER, f_upper(y), f_info(y));
      ru = Boundary_NS::assign(UPPER, upper(), info(), UPPER, f_upper(x), f_info(x));
    }
  }
  else if (nu) {
    ru = complement(UPPER, upper(), info(), LOWER, f_lower(y), f_info(y));
    rl = Boundary_NS::assign(LOWER, lower(), info(), LOWER, f_lower(x), f_info(x));
  }
  assign_or_swap(info(), to_info);
  complete_init_internal();
  assert(OK());
  return combine(rl, ru);
}

template <typename To_Boundary, typename To_Info>
template <typename From>
inline typename Enable_If<Is_Singleton<From>::value
                          || Is_Interval<From>::value, I_Result>::type
Interval<To_Boundary, To_Info>
::refine_existential(Relation_Symbol rel, const From& x) {
  assert(OK());
  assert(f_OK(x));
  if (check_empty_arg(x))
    return assign(EMPTY);
  switch (rel) {
  case LESS_THAN:
    {
      if (lt(UPPER, upper(), info(), UPPER, f_upper(x), f_info(x)))
	return combine(V_EQ, V_EQ);
      info().clear_boundary_properties(UPPER);
      Result ru = Boundary_NS::assign(UPPER, upper(), info(),
				      UPPER, f_upper(x), f_info(x), true);
      invalidate_cardinality_cache();
      normalize();
      // The following Parma_Polyhedra_Library:: qualification is to work
      // around a bug in version 10.0 of the Intel C/C++ compiler.
      return Parma_Polyhedra_Library::check_empty_result(*this,
							 combine(V_EQ, ru));
    }
  case LESS_OR_EQUAL:
    {
      if (le(UPPER, upper(), info(), UPPER, f_upper(x), f_info(x)))
	return combine(V_EQ, V_EQ);
      info().clear_boundary_properties(UPPER);
      Result ru = Boundary_NS::assign(UPPER, upper(), info(),
				      UPPER, f_upper(x), f_info(x));
      invalidate_cardinality_cache();
      normalize();
      // The following Parma_Polyhedra_Library:: qualification is to work
      // around a bug in version 10.0 of the Intel C/C++ compiler.
      return Parma_Polyhedra_Library::check_empty_result(*this,
							 combine(V_EQ, ru));
    }
  case GREATER_THAN:
    {
      if (gt(LOWER, lower(), info(), LOWER, f_lower(x), f_info(x)))
	return combine(V_EQ, V_EQ);
      info().clear_boundary_properties(LOWER);
      Result rl = Boundary_NS::assign(LOWER, lower(), info(),
				      LOWER, f_lower(x), f_info(x), true);
      invalidate_cardinality_cache();
      normalize();
      // The following Parma_Polyhedra_Library:: qualification is to work
      // around a bug in version 10.0 of the Intel C/C++ compiler.
      return Parma_Polyhedra_Library::check_empty_result(*this,
							 combine(rl, V_EQ));
    }
  case GREATER_OR_EQUAL:
    {
      if (ge(LOWER, lower(), info(), LOWER, f_lower(x), f_info(x)))
	return combine(V_EQ, V_EQ);
      info().clear_boundary_properties(LOWER);
      Result rl = Boundary_NS::assign(LOWER, lower(), info(),
				      LOWER, f_lower(x), f_info(x));
      invalidate_cardinality_cache();
      normalize();
      // The following Parma_Polyhedra_Library:: qualification is to work
      // around a bug in version 10.0 of the Intel C/C++ compiler.
      return Parma_Polyhedra_Library::check_empty_result(*this,
							 combine(rl, V_EQ));
    }
  case EQUAL:
    return intersect_assign(x);
  case NOT_EQUAL:
    {
      if (!f_is_singleton(x))
	return combine(V_EQ, V_EQ);
      if (check_empty_arg(*this))
	return I_EMPTY;
      if (eq(LOWER, lower(), info(), LOWER, f_lower(x), f_info(x)))
	lower_shrink();
      if (eq(UPPER, upper(), info(), UPPER, f_upper(x), f_info(x)))
	upper_shrink();
      invalidate_cardinality_cache();
      normalize();
      // The following Parma_Polyhedra_Library:: qualification is to work
      // around a bug in version 10.0 of the Intel C/C++ compiler.
      return Parma_Polyhedra_Library::check_empty_result(*this,
							 combine(V_EQ, V_EQ));
    }
  default:
    assert(false);
    return I_EMPTY;
  }
}

template <typename To_Boundary, typename To_Info>
template <typename From>
inline typename Enable_If<Is_Singleton<From>::value
                          || Is_Interval<From>::value, I_Result>::type
Interval<To_Boundary, To_Info>::refine_universal(Relation_Symbol rel,
                                                 const From& x) {
  assert(OK());
  assert(f_OK(x));
  if (check_empty_arg(x))
    return combine(V_EQ, V_EQ);
  switch (rel) {
  case LESS_THAN:
    {
      if (lt(UPPER, upper(), info(), LOWER, f_lower(x), f_info(x)))
	return combine(V_EQ, V_EQ);
      info().clear_boundary_properties(UPPER);
      Result ru = Boundary_NS::assign(UPPER, upper(), info(),
				      LOWER, f_lower(x), SCALAR_INFO, !is_open(LOWER, f_lower(x), f_info(x)));
      invalidate_cardinality_cache();
      normalize();
      // The following Parma_Polyhedra_Library:: qualification is to work
      // around a bug in version 10.0 of the Intel C/C++ compiler.
      return Parma_Polyhedra_Library::check_empty_result(*this,
							 combine(V_EQ, ru));
    }
  case LESS_OR_EQUAL:
    {
      if (le(UPPER, upper(), info(), LOWER, f_lower(x), f_info(x)))
	return combine(V_EQ, V_EQ);
      info().clear_boundary_properties(UPPER);
      Result ru = Boundary_NS::assign(UPPER, upper(), info(),
				      LOWER, f_lower(x), SCALAR_INFO);
      invalidate_cardinality_cache();
      normalize();
      // The following Parma_Polyhedra_Library:: qualification is to work
      // around a bug in version 10.0 of the Intel C/C++ compiler.
      return Parma_Polyhedra_Library::check_empty_result(*this,
							 combine(V_EQ, ru));
    }
  case GREATER_THAN:
    {
      if (gt(LOWER, lower(), info(), UPPER, f_upper(x), f_info(x)))
	return combine(V_EQ, V_EQ);
      info().clear_boundary_properties(LOWER);
      Result rl = Boundary_NS::assign(LOWER, lower(), info(),
				      UPPER, f_upper(x), SCALAR_INFO, !is_open(UPPER, f_upper(x), f_info(x)));
      invalidate_cardinality_cache();
      normalize();
      // The following Parma_Polyhedra_Library:: qualification is to work
      // around a bug in version 10.0 of the Intel C/C++ compiler.
      return Parma_Polyhedra_Library::check_empty_result(*this,
							 combine(rl, V_EQ));
    }
  case GREATER_OR_EQUAL:
    {
      if (ge(LOWER, lower(), info(), UPPER, f_upper(x), f_info(x)))
	return combine(V_EQ, V_EQ);
      info().clear_boundary_properties(LOWER);
      Result rl = Boundary_NS::assign(LOWER, lower(), info(),
				      UPPER, f_upper(x), SCALAR_INFO);
      invalidate_cardinality_cache();
      normalize();
      // The following Parma_Polyhedra_Library:: qualification is to work
      // around a bug in version 10.0 of the Intel C/C++ compiler.
      return Parma_Polyhedra_Library::check_empty_result(*this,
							 combine(rl, V_EQ));
    }
  case EQUAL:
    if (!f_is_singleton(x))
      return assign(EMPTY);
    return intersect_assign(x);
  case NOT_EQUAL:
    {
      if (check_empty_arg(*this))
	return I_EMPTY;
      if (eq(LOWER, lower(), info(), LOWER, f_lower(x), f_info(x)))
	lower_shrink();
      if (eq(UPPER, upper(), info(), UPPER, f_upper(x), f_info(x)))
	upper_shrink();
      invalidate_cardinality_cache();
      normalize();
      // The following Parma_Polyhedra_Library:: qualification is to work
      // around a bug in version 10.0 of the Intel C/C++ compiler.
      return Parma_Polyhedra_Library::check_empty_result(*this,
							 combine(V_EQ, V_EQ));
    }
  default:
    assert(false);
    return I_EMPTY;
  }
}

template <typename To_Boundary, typename To_Info>
template <typename From>
inline typename Enable_If<Is_Singleton<From>::value
                          || Is_Interval<From>::value, I_Result>::type
Interval<To_Boundary, To_Info>::neg_assign(const From& x) {
  assert(f_OK(x));
  if (check_empty_arg(x))
    return assign(EMPTY);
  PPL_DIRTY_TEMP(To_Info, to_info);
  to_info.clear();
  if (!neg_restriction(to_info, x))
    return assign(EMPTY);
  Result rl, ru;
  PPL_DIRTY_TEMP(To_Boundary, to_lower);
  rl = Boundary_NS::neg_assign(LOWER, to_lower, to_info, UPPER, f_upper(x), f_info(x));
  ru = Boundary_NS::neg_assign(UPPER, upper(), to_info, LOWER, f_lower(x), f_info(x));
  assign_or_swap(lower(), to_lower);
  assign_or_swap(info(), to_info);
  complete_init_internal();
  assert(OK());
  return combine(rl, ru);
}

template <typename To_Boundary, typename To_Info>
template <typename From1, typename From2>
inline typename Enable_If<((Is_Singleton<From1>::value
                            || Is_Interval<From1>::value)
			   && (Is_Singleton<From2>::value
                               || Is_Interval<From2>::value)), I_Result>::type
Interval<To_Boundary, To_Info>::add_assign(const From1& x, const From2& y) {
  assert(f_OK(x));
  assert(f_OK(y));
  if (check_empty_arg(x) || check_empty_arg(y))
    return assign(EMPTY);
  int inf = Parma_Polyhedra_Library::is_infinity(x);
  if (inf) {
    if (Parma_Polyhedra_Library::is_infinity(y) == -inf)
      return assign(EMPTY);
  }
  else
    inf = Parma_Polyhedra_Library::is_infinity(y);
  if (inf < 0)
    return assign(MINUS_INFINITY);
  else if (inf > 0)
    return assign(PLUS_INFINITY);
  PPL_DIRTY_TEMP(To_Info, to_info);
  to_info.clear();
  if (!add_restriction(to_info, x, y))
    return assign(EMPTY);
  Result rl = Boundary_NS::add_assign(LOWER, lower(), to_info,
				      LOWER, f_lower(x), f_info(x),
				      LOWER, f_lower(y), f_info(y));
  Result ru = Boundary_NS::add_assign(UPPER, upper(), to_info,
				      UPPER, f_upper(x), f_info(x),
				      UPPER, f_upper(y), f_info(y));
  assign_or_swap(info(), to_info);
  complete_init_internal();
  assert(OK());
  return combine(rl, ru);
}

template <typename To_Boundary, typename To_Info>
template <typename From1, typename From2>
inline typename Enable_If<((Is_Singleton<From1>::value
                            || Is_Interval<From1>::value)
			   && (Is_Singleton<From2>::value
                               || Is_Interval<From2>::value)), I_Result>::type
Interval<To_Boundary, To_Info>::sub_assign(const From1& x, const From2& y) {
  assert(f_OK(x));
  assert(f_OK(y));
  if (check_empty_arg(x) || check_empty_arg(y))
    return assign(EMPTY);
  int inf = Parma_Polyhedra_Library::is_infinity(x);
  if (inf) {
    if (Parma_Polyhedra_Library::is_infinity(y) == inf)
      return assign(EMPTY);
  }
  else
    inf = -Parma_Polyhedra_Library::is_infinity(y);
  if (inf < 0)
    return assign(MINUS_INFINITY);
  else if (inf > 0)
    return assign(PLUS_INFINITY);

  PPL_DIRTY_TEMP(To_Info, to_info);
  to_info.clear();
  if (!sub_restriction(to_info, x, y))
    return assign(EMPTY);
  Result rl, ru;
  PPL_DIRTY_TEMP(To_Boundary, to_lower);
  rl = Boundary_NS::sub_assign(LOWER, to_lower, to_info,
			       LOWER, f_lower(x), f_info(x),
			       UPPER, f_upper(y), f_info(y));
  ru = Boundary_NS::sub_assign(UPPER, upper(), to_info,
			       UPPER, f_upper(x), f_info(x),
			       LOWER, f_lower(y), f_info(y));
  assign_or_swap(lower(), to_lower);
  assign_or_swap(info(), to_info);
  complete_init_internal();
  assert(OK());
  return combine(rl, ru);
}

/**
+---------+-----------+-----------+-----------------+
|    *    |  yl > 0   |  yu < 0   |  yl < 0, yu > 0 |
+---------+-----------+-----------+-----------------+
| xl > 0  |xl*yl,xu*yu|xu*yl,xl*yu|   xu*yl,xu*yu   |
+---------+-----------+-----------+-----------------+
| xu < 0  |xl*yu,xu*yl|xu*yu,xl*yl|   xl*yu,xl*yl   |
+---------+-----------+-----------+-----------------+
|xl<0 xu>0|xl*yu,xu*yu|xu*yl,xl*yl|min(xl*yu,xu*yl),|
|         |           |           |max(xl*yl,xu*yu) |
+---------+-----------+-----------+-----------------+
**/
template <typename To_Boundary, typename To_Info>
template <typename From1, typename From2>
inline typename Enable_If<((Is_Singleton<From1>::value
                            || Is_Interval<From1>::value)
			   && (Is_Singleton<From2>::value
                               || Is_Interval<From2>::value)), I_Result>::type
Interval<To_Boundary, To_Info>::mul_assign(const From1& x, const From2& y) {
  assert(f_OK(x));
  assert(f_OK(y));
  if (check_empty_arg(x) || check_empty_arg(y))
    return assign(EMPTY);
  int xls = sgn_b(LOWER, f_lower(x), f_info(x));
  int xus = xls > 0 ? 1 : sgn_b(UPPER, f_upper(x), f_info(x));
  int yls = sgn_b(LOWER, f_lower(y), f_info(y));
  int yus = yls > 0 ? 1 : sgn_b(UPPER, f_upper(y), f_info(y));
  int inf = Parma_Polyhedra_Library::is_infinity(x);
  int ls, us;
  if (inf) {
    ls = yls;
    us = yus;
    goto inf;
  }
  else {
    inf = Parma_Polyhedra_Library::is_infinity(y);
    if (inf) {
      ls = xls;
      us = xus;
    inf:
      if (ls == 0 && us == 0)
	return assign(EMPTY);
      if (ls == -us)
	return set_infinities();
      if (ls < 0 || us < 0)
	inf = -inf;
      if (inf < 0)
	return assign(MINUS_INFINITY);
      else
	return assign(PLUS_INFINITY);
    }
  }

  PPL_DIRTY_TEMP(To_Info, to_info);
  to_info.clear();
  if (!mul_restriction(to_info, x, y))
    return assign(EMPTY);
  Result rl, ru;
  PPL_DIRTY_TEMP(To_Boundary, to_lower);

  if (xls >= 0) {
    if (yls >= 0) {
      // 0 <= xl <= xu, 0 <= yl <= yu
      rl = mul_assign_z(LOWER, to_lower, to_info,
			LOWER, f_lower(x), f_info(x), xls,
			LOWER, f_lower(y), f_info(y), yls);
      ru = mul_assign_z(UPPER, upper(), to_info,
			UPPER, f_upper(x), f_info(x), xus,
			UPPER, f_upper(y), f_info(y), yus);
    }
    else if (yus <= 0) {
      // 0 <= xl <= xu, yl <= yu <= 0
      rl = mul_assign_z(LOWER, to_lower, to_info,
			UPPER, f_upper(x), f_info(x), xus,
			LOWER, f_lower(y), f_info(y), yls);
      ru = mul_assign_z(UPPER, upper(), to_info,
			LOWER, f_lower(x), f_info(x), xls,
			UPPER, f_upper(y), f_info(y), yus);
    }
    else {
      // 0 <= xl <= xu, yl < 0 < yu
      rl = mul_assign_z(LOWER, to_lower, to_info,
			UPPER, f_upper(x), f_info(x), xus,
			LOWER, f_lower(y), f_info(y), yls);
      ru = mul_assign_z(UPPER, upper(), to_info,
			UPPER, f_upper(x), f_info(x), xus,
			UPPER, f_upper(y), f_info(y), yus);
    }
  }
  else if (xus <= 0) {
    if (yls >= 0) {
      // xl <= xu <= 0, 0 <= yl <= yu
      rl = mul_assign_z(LOWER, to_lower, to_info,
			LOWER, f_lower(x), f_info(x), xls,
			UPPER, f_upper(y), f_info(y), yus);
      ru = mul_assign_z(UPPER, upper(), to_info,
			UPPER, f_upper(x), f_info(x), xus,
			LOWER, f_lower(y), f_info(y), yls);
    }
    else if (yus <= 0) {
      // xl <= xu <= 0, yl <= yu <= 0
      rl = mul_assign_z(LOWER, to_lower, to_info,
			UPPER, f_upper(x), f_info(x), xus,
			UPPER, f_upper(y), f_info(y), yus);
      ru = mul_assign_z(UPPER, upper(), to_info,
			LOWER, f_lower(x), f_info(x), xls,
			LOWER, f_lower(y), f_info(y), yls);
    }
    else {
      // xl <= xu <= 0, yl < 0 < yu
      rl = mul_assign_z(LOWER, to_lower, to_info,
			LOWER, f_lower(x), f_info(x), xls,
			UPPER, f_upper(y), f_info(y), yus);
      ru = mul_assign_z(UPPER, upper(), to_info,
			LOWER, f_lower(x), f_info(x), xls,
			LOWER, f_lower(y), f_info(y), yls);
    }
  }
  else if (yls >= 0) {
    // xl < 0 < xu, 0 <= yl <= yu
    rl = mul_assign_z(LOWER, to_lower, to_info,
		      LOWER, f_lower(x), f_info(x), xls,
		      UPPER, f_upper(y), f_info(y), yus);
    ru = mul_assign_z(UPPER, upper(), to_info,
		      UPPER, f_upper(x), f_info(x), xus,
		      UPPER, f_upper(y), f_info(y), yus);
  }
  else if (yus <= 0) {
    // xl < 0 < xu, yl <= yu <= 0
    rl = mul_assign_z(LOWER, to_lower, to_info,
		      UPPER, f_upper(x), f_info(x), xus,
		      LOWER, f_lower(y), f_info(y), yls);
    ru = mul_assign_z(UPPER, upper(), to_info,
		      LOWER, f_lower(x), f_info(x), xls,
		      LOWER, f_lower(y), f_info(y), yls);
  }
  else {
    // xl < 0 < xu, yl < 0 < yu
    PPL_DIRTY_TEMP(To_Boundary, tmp);
    PPL_DIRTY_TEMP(To_Info, tmp_info);
    tmp_info.clear();
    Result tmp_r;
    tmp_r = Boundary_NS::mul_assign(LOWER, tmp, tmp_info,
				    UPPER, f_upper(x), f_info(x),
				    LOWER, f_lower(y), f_info(y));
    rl = Boundary_NS::mul_assign(LOWER, to_lower, to_info,
				 LOWER, f_lower(x), f_info(x),
				 UPPER, f_upper(y), f_info(y));
    if (gt(LOWER, to_lower, to_info, LOWER, tmp, tmp_info)) {
      to_lower = tmp;
      rl = tmp_r;
    }
    tmp_info.clear();
    tmp_r = Boundary_NS::mul_assign(UPPER, tmp, tmp_info,
				    UPPER, f_upper(x), f_info(x),
				    UPPER, f_upper(y), f_info(y));
    ru = Boundary_NS::mul_assign(UPPER, upper(), to_info,
				 LOWER, f_lower(x), f_info(x),
				 LOWER, f_lower(y), f_info(y));
    if (lt(UPPER, upper(), to_info, UPPER, tmp, tmp_info)) {
      upper() = tmp;
      ru = tmp_r;
    }
  }
  assign_or_swap(lower(), to_lower);
  assign_or_swap(info(), to_info);
  complete_init_internal();
  assert(OK());
  return combine(rl, ru);
}

/**
+-----------+-----------+-----------+
|     /     |  yu < 0   |  yl > 0   |
+-----------+-----------+-----------+
|   xu<=0   |xu/yl,xl/yu|xl/yl,xu/yu|
+-----------+-----------+-----------+
|xl<=0 xu>=0|xu/yu,xl/yu|xl/yl,xu/yl|
+-----------+-----------+-----------+
|   xl>=0   |xu/yu,xl/yl|xl/yu,xu/yl|
+-----------+-----------+-----------+
**/
template <typename To_Boundary, typename To_Info>
template <typename From1, typename From2>
inline typename Enable_If<((Is_Singleton<From1>::value
                            || Is_Interval<From1>::value)
			   && (Is_Singleton<From2>::value
                               || Is_Interval<From2>::value)), I_Result>::type
Interval<To_Boundary, To_Info>::div_assign(const From1& x, const From2& y) {
  assert(f_OK(x));
  assert(f_OK(y));
  if (check_empty_arg(x) || check_empty_arg(y))
    return assign(EMPTY);
  int yls = sgn_b(LOWER, f_lower(y), f_info(y));
  int yus = yls > 0 ? 1 : sgn_b(UPPER, f_upper(y), f_info(y));
  if (yls == 0 && yus == 0)
    return assign(EMPTY);
  int inf = Parma_Polyhedra_Library::is_infinity(x);
  if (inf) {
    if (Parma_Polyhedra_Library::is_infinity(y))
      return assign(EMPTY);
    if (yls == -yus)
      return set_infinities();
    if (yls < 0 || yus < 0)
      inf = -inf;
    if (inf < 0)
      return assign(MINUS_INFINITY);
    else
      return assign(PLUS_INFINITY);
  }
  int xls = sgn_b(LOWER, f_lower(x), f_info(x));
  int xus = xls > 0 ? 1 : sgn_b(UPPER, f_upper(x), f_info(x));

  PPL_DIRTY_TEMP(To_Info, to_info);
  to_info.clear();
  if (!div_restriction(to_info, x, y))
    return assign(EMPTY);
  Result rl, ru;
  PPL_DIRTY_TEMP(To_Boundary, to_lower);
  if (yls >= 0) {
    if (xls >= 0) {
      rl = div_assign_z(LOWER, to_lower, to_info,
			LOWER, f_lower(x), f_info(x), xls,
			UPPER, f_upper(y), f_info(y), yus);
      ru = div_assign_z(UPPER, upper(), to_info,
			UPPER, f_upper(x), f_info(x), xus,
			LOWER, f_lower(y), f_info(y), yls);
    }
    else if (xus <= 0) {
      rl = div_assign_z(LOWER, to_lower, to_info,
			LOWER, f_lower(x), f_info(x), xls,
			LOWER, f_lower(y), f_info(y), yls);
      ru = div_assign_z(UPPER, upper(), to_info,
			UPPER, f_upper(x), f_info(x), xus,
			UPPER, f_upper(y), f_info(y), yus);
    }
    else {
      rl = div_assign_z(LOWER, to_lower, to_info,
			LOWER, f_lower(x), f_info(x), xls,
			LOWER, f_lower(y), f_info(y), yls);
      ru = div_assign_z(UPPER, upper(), to_info,
			UPPER, f_upper(x), f_info(x), xus,
			LOWER, f_lower(y), f_info(y), yls);
    }
  }
  else if (yus <= 0) {
    if (xls >= 0) {
      rl = div_assign_z(LOWER, to_lower, to_info,
			UPPER, f_upper(x), f_info(x), xus,
			UPPER, f_upper(y), f_info(y), yus);
      ru = div_assign_z(UPPER, upper(), to_info,
			LOWER, f_lower(x), f_info(x), xls,
			LOWER, f_lower(y), f_info(y), yls);
    }
    else if (xus <= 0) {
      rl = div_assign_z(LOWER, to_lower, to_info,
			UPPER, f_upper(x), f_info(x), xus,
			LOWER, f_lower(y), f_info(y), yls);
      ru = div_assign_z(UPPER, upper(), to_info,
			LOWER, f_lower(x), f_info(x), xls,
			UPPER, f_upper(y), f_info(y), yus);
    }
    else {
      rl = div_assign_z(LOWER, to_lower, to_info,
			UPPER, f_upper(x), f_info(x), xus,
			UPPER, f_upper(y), f_info(y), yus);
      ru = div_assign_z(UPPER, upper(), to_info,
			LOWER, f_lower(x), f_info(x), xls,
			UPPER, f_upper(y), f_info(y), yus);
    }
  }
  else {
    // FIXME: restrictions
    return static_cast<I_Result>(assign(UNIVERSE) | I_SINGULARITIES);
  }
  assign_or_swap(lower(), to_lower);
  assign_or_swap(info(), to_info);
  complete_init_internal();
  assert(OK());
  return combine(rl, ru);
}

template <typename B, typename Info, typename T>
inline typename Enable_If<Is_Singleton<T>::value, Interval<B, Info> >::type
operator+(const Interval<B, Info>& x, const T& y) {
  Interval<B, Info> z;
  z.add_assign(x, y);
  return z;
}

template <typename B, typename Info, typename T>
inline typename Enable_If<Is_Singleton<T>::value, Interval<B, Info> >::type
operator+(const T& x, const Interval<B, Info>& y) {
  Interval<B, Info> z;
  z.add_assign(x, y);
  return z;
}

template <typename B, typename Info>
inline Interval<B, Info>
operator+(const Interval<B, Info>& x, const Interval<B, Info>& y) {
  Interval<B, Info> z;
  z.add_assign(x, y);
  return z;
}

template <typename B, typename Info, typename T>
inline typename Enable_If<Is_Singleton<T>::value, Interval<B, Info> >::type
operator-(const Interval<B, Info>& x, const T& y) {
  Interval<B, Info> z;
  z.sub_assign(x, y);
  return z;
}

template <typename B, typename Info, typename T>
inline typename Enable_If<Is_Singleton<T>::value, Interval<B, Info> >::type
operator-(const T& x, const Interval<B, Info>& y) {
  Interval<B, Info> z;
  z.sub_assign(x, y);
  return z;
}

template <typename B, typename Info>
inline Interval<B, Info>
operator-(const Interval<B, Info>& x, const Interval<B, Info>& y) {
  Interval<B, Info> z;
  z.sub_assign(x, y);
  return z;
}

template <typename B, typename Info, typename T>
inline typename Enable_If<Is_Singleton<T>::value, Interval<B, Info> >::type
operator*(const Interval<B, Info>& x, const T& y) {
  Interval<B, Info> z;
  z.mul_assign(x, y);
  return z;
}

template <typename B, typename Info, typename T>
inline typename Enable_If<Is_Singleton<T>::value, Interval<B, Info> >::type
operator*(const T& x, const Interval<B, Info>& y) {
  Interval<B, Info> z;
  z.mul_assign(x, y);
  return z;
}

template <typename B, typename Info>
inline Interval<B, Info>
operator*(const Interval<B, Info>& x, const Interval<B, Info>& y) {
  Interval<B, Info> z;
  z.mul_assign(x, y);
  return z;
}

template <typename B, typename Info, typename T>
inline typename Enable_If<Is_Singleton<T>::value, Interval<B, Info> >::type
operator/(const Interval<B, Info>& x, const T& y) {
  Interval<B, Info> z;
  z.div_assign(x, y);
  return z;
}

template <typename B, typename Info, typename T>
inline typename Enable_If<Is_Singleton<T>::value, Interval<B, Info> >::type
operator/(const T& x, const Interval<B, Info>& y) {
  Interval<B, Info> z;
  z.div_assign(x, y);
  return z;
}

template <typename B, typename Info>
inline Interval<B, Info>
operator/(const Interval<B, Info>& x, const Interval<B, Info>& y) {
  Interval<B, Info> z;
  z.div_assign(x, y);
  return z;
}

template <typename Boundary, typename Info>
inline std::ostream&
operator<<(std::ostream& os, const Interval<Boundary, Info>& x) {
  // assert(x.OK());
  if (check_empty_arg(x))
    return os << "[]";
  if (x.is_singleton()) {
    output(os, x.lower(), Numeric_Format(), ROUND_NOT_NEEDED);
    return os;
  }
  os << (x.lower_is_open() ? "(" : "[");
  if (x.info().get_boundary_property(LOWER, SPECIAL))
    os << "-inf";
  else
    output(os, x.lower(), Numeric_Format(), ROUND_NOT_NEEDED);
  os << ", ";
  if (x.info().get_boundary_property(UPPER, SPECIAL))
    os << "+inf";
  else
    output(os, x.upper(), Numeric_Format(), ROUND_NOT_NEEDED);
  os << (x.upper_is_open() ? ")" : "]");
  output_restriction(os, x.info());
  return os;
}

template <typename Boundary, typename Info>
inline void
Interval<Boundary, Info>::ascii_dump(std::ostream& s) const {
  using Parma_Polyhedra_Library::ascii_dump;
  s << "info ";
  info().ascii_dump(s);
  s << " lower ";
  ascii_dump(s, lower());
  s << " upper ";
  ascii_dump(s, upper());
  s << '\n';
}

template <typename Boundary, typename Info>
inline bool
Interval<Boundary, Info>::ascii_load(std::istream& s) {
  using Parma_Polyhedra_Library::ascii_load;
  std::string str;
  if (!(s >> str) || str != "info")
    return false;
  if (!info().ascii_load(s))
    return false;
  if (!(s >> str) || str != "lower")
    return false;
  if (!ascii_load(s, lower()))
    return false;
  if (!(s >> str) || str != "upper")
    return false;
  if (!ascii_load(s, upper()))
    return false;
#ifdef PPL_ABI_BREAKING_EXTRA_DEBUG
  complete_init_internal();
#endif
  assert(OK());
  return true;
}

/*! \brief
  Helper class to select the appropriate numerical type to perform
  boundary computations so as to reduce the chances of overflow without
  incurring too much overhead.
*/
template <typename Interval_Boundary_Type> struct Select_Temp_Boundary_Type;

template <typename Interval_Boundary_Type>
struct Select_Temp_Boundary_Type {
  typedef Interval_Boundary_Type type;
};

template <>
struct Select_Temp_Boundary_Type<float> {
  typedef double type;
};

template <>
struct Select_Temp_Boundary_Type<signed char> {
  typedef signed long long type;
};

template <>
struct Select_Temp_Boundary_Type<unsigned char> {
  typedef signed long long type;
};

template <>
struct Select_Temp_Boundary_Type<signed short> {
  typedef signed long long type;
};

template <>
struct Select_Temp_Boundary_Type<unsigned short> {
  typedef signed long long type;
};

template <>
struct Select_Temp_Boundary_Type<signed int> {
  typedef signed long long type;
};

template <>
struct Select_Temp_Boundary_Type<unsigned int> {
  typedef signed long long type;
};

template <>
struct Select_Temp_Boundary_Type<signed long> {
  typedef signed long long type;
};

template <>
struct Select_Temp_Boundary_Type<unsigned long> {
  typedef signed long long type;
};

template <>
struct Select_Temp_Boundary_Type<unsigned long long> {
  typedef signed long long type;
};

} // namespace Parma_Polyhedra_Library

namespace std {

/*! \relates Parma_Polyhedra_Library::Interval */
template <typename Boundary, typename Info>
inline void
swap(Parma_Polyhedra_Library::Interval<Boundary, Info>& x,
     Parma_Polyhedra_Library::Interval<Boundary, Info>& y) {
  x.swap(y);
}

} // namespace std

/* Automatically generated from PPL source file ../src/Interval.templates.hh line 1. */
/* Interval class implementation: non-inline template functions.
*/


#include <algorithm>

namespace Parma_Polyhedra_Library {

template <typename Boundary, typename Info>
template <typename From, typename Iterator>
typename Enable_If<Is_Interval<From>::value, void>::type
Interval<Boundary, Info>::CC76_widening_assign(const From& y,
					       Iterator first,
					       Iterator last) {
  // We assume that `y' is contained in or equal to `*this'.
  assert(contains(y));
  Interval<Boundary, Info>& x = *this;

  // Upper bound.
  if (!x.upper_is_unbounded()) {
    Boundary& x_ub = x.upper();
    const Boundary& y_ub = y.upper();
    assert(!y.upper_is_unbounded() && y_ub <= x_ub);
    if (y_ub < x_ub) {
      Iterator k = std::lower_bound(first, last, x_ub);
      if (k != last) {
	if (x_ub < *k)
	  x_ub = *k;
      }
      else
	x.upper_set(UNBOUNDED);
    }
  }

  // Lower bound.
  if (!x.lower_is_unbounded()) {
    Boundary& x_lb = x.lower();
    const Boundary& y_lb = y.lower();
    assert(!y.lower_is_unbounded() && y_lb >= x_lb);
    if (y_lb > x_lb) {
      Iterator k = std::lower_bound(first, last, x_lb);
      if (k != last) {
	if (x_lb < *k) {
	  if (k != first)
	    x_lb = *--k;
	  else
	    x.lower_set(UNBOUNDED);
	}
      }
      else
	x_lb = *--k;
    }
  }
}

template <typename Boundary, typename Info>
inline std::istream&
operator>>(std::istream& is, Interval<Boundary, Info>& x) {
  // Eat leading white space.
  int c;
  do {
    c = is.get();
  } while (isspace(c));

  // Get the opening parenthesis and handle the empty interval case.
  bool lower_open = false;
  if (c == '(')
    lower_open = true;
  else if (c == '[') {
    c = is.get();
    if (c == ']') {
      // Empty interval.
      x.assign(EMPTY);
      return is;
    }
    else
      is.unget();
  }
  else {
    is.unget();
    is.setstate(std::ios_base::failbit);
    return is;
  }

  // Get the lower bound.
  Boundary lower_bound;
  Result lower_r  = input(lower_bound, is, ROUND_DOWN);
  if (lower_r == V_CVT_STR_UNK || lower_r == VC_NAN) {
    is.setstate(std::ios_base::failbit);
    return is;
  }

  // Match the comma separating the lower and upper bounds.
  do {
    c = is.get();
  } while (isspace(c));
  if (c != ',') {
    is.unget();
    is.setstate(std::ios_base::failbit);
    return is;
  }

  // Get the upper bound.
  Boundary upper_bound;
  Result upper_r = input(upper_bound, is, ROUND_UP);
  if (upper_r == V_CVT_STR_UNK || upper_r == VC_NAN) {
    is.setstate(std::ios_base::failbit);
    return is;
  }

  // Get the closing parenthesis.
  do {
    c = is.get();
  } while (isspace(c));
  bool upper_open = false;
  if (c == ')')
    upper_open = true;
  else if (c != ']') {
    is.unget();
    is.setstate(std::ios_base::failbit);
    return is;
  }

  // Buld interval.
  bool lower_unbounded = false;
  bool upper_unbounded = false;
  switch (lower_r) {
  case V_EQ:
    break;
  case V_LE:
    lower_open = true;
    break;
  case VC_MINUS_INFINITY:
  case V_NEG_OVERFLOW:
    lower_unbounded = true;
    break;
  case VC_PLUS_INFINITY:
  case V_POS_OVERFLOW:
    if (upper_r == VC_PLUS_INFINITY || upper_r == V_POS_OVERFLOW)
      x.assign(UNIVERSE);
    else
      x.assign(EMPTY);
    return is;
  default:
    assert(false);
  }
  switch (upper_r) {
  case V_EQ:
    break;
  case V_GE:
    upper_open = true;
    break;
  case VC_MINUS_INFINITY:
  case V_NEG_OVERFLOW:
    if (lower_r == VC_MINUS_INFINITY || lower_r == V_NEG_OVERFLOW)
      x.assign(UNIVERSE);
    else
      x.assign(EMPTY);
    return is;
  case VC_PLUS_INFINITY:
  case V_POS_OVERFLOW:
    upper_unbounded = true;
    break;
  default:
    assert(false);
  }

  if (!lower_unbounded
      && !upper_unbounded
      && (lower_bound > upper_bound
	  || (lower_open && lower_bound == upper_bound)))
    x.assign(EMPTY);
  else {
    x.assign(UNIVERSE);
    if (!lower_unbounded)
      x.refine_existential((lower_open ? GREATER_THAN : GREATER_OR_EQUAL),
			   lower_bound);
    if (!upper_unbounded)
      x.refine_existential((upper_open ? LESS_THAN : LESS_OR_EQUAL),
			   upper_bound);
  }
  return is;
}

template <typename Boundary, typename Info>
template <typename From>
typename Enable_If<Is_Interval<From>::value, bool>::type
Interval<Boundary, Info>::simplify_using_context_assign(const From& y) {
  // FIXME: the following code wrongly assumes that intervals are closed
  // and have no restrictions. It must be generalized.
  if (lt(UPPER, upper(), info(), LOWER, f_lower(y), f_info(y))) {
    lower_set(UNBOUNDED);
    return false;
  }
  if (gt(LOWER, lower(), info(), UPPER, f_upper(y), f_info(y))) {
    upper_set(UNBOUNDED);
    return false;
  }
  // Weakening the upper bound.
  if (!upper_is_unbounded() && !y.upper_is_unbounded()
      && y.upper() <= upper())
    upper_set(UNBOUNDED);
  // Weakening the lower bound.
  if (!lower_is_unbounded() && !y.lower_is_unbounded()
      && y.lower() >= lower())
    lower_set(UNBOUNDED);
  return true;
}

template <typename Boundary, typename Info>
template <typename From>
typename Enable_If<Is_Interval<From>::value, void>::type
Interval<Boundary, Info>::empty_intersection_assign(const From&) {
  // FIXME: write me.
  assign(EMPTY);
}

} // namespace Parma_Polyhedra_Library

/* Automatically generated from PPL source file ../src/Interval.defs.hh line 982. */

/* Automatically generated from PPL source file ../src/Rational_Interval.hh line 27. */
#include <gmpxx.h>

namespace Parma_Polyhedra_Library {

struct Rational_Interval_Info_Policy {
  const_bool_nodef(store_special, true);
  const_bool_nodef(store_open, true);
  const_bool_nodef(cache_empty, true);
  const_bool_nodef(cache_singleton, true);
  const_bool_nodef(cache_normalized, false);
  const_int_nodef(next_bit, 0);
  const_bool_nodef(may_be_empty, true);
  const_bool_nodef(may_contain_infinity, false);
  const_bool_nodef(check_empty_result, false);
  const_bool_nodef(check_inexact, false);
};

typedef
Interval_Restriction_None<Interval_Info_Bitset<unsigned int,
                                               Rational_Interval_Info_Policy> >
Rational_Interval_Info;

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! An interval with rational, possibly open boundaries.
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
typedef Interval<mpq_class, Rational_Interval_Info> Rational_Interval;

} // namespace Parma_Polyhedra_Library

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


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


namespace Parma_Polyhedra_Library {

template <typename D1, typename D2>
class Smash_Reduction;

template <typename D1, typename D2>
class Constraints_Reduction;

template <typename D1, typename D2>
class No_Reduction;

template <typename D1, typename D2, typename R>
class Partially_Reduced_Product;

} // namespace Parma_Polyhedra_Library

/* Automatically generated from PPL source file ../src/Box.defs.hh line 46. */
#include <vector>
#include <iosfwd>

namespace Parma_Polyhedra_Library {

//! Returns <CODE>true</CODE> if and only if \p x and \p y are the same box.
/*! \relates Box
  Note that \p x and \p y may be dimension-incompatible boxes:
  in this case, the value <CODE>false</CODE> is returned.
*/
template <typename ITV>
bool operator==(const Box<ITV>& x, const Box<ITV>& y);

//! Returns <CODE>true</CODE> if and only if \p x and \p y aren't the same box.
/*! \relates Box
  Note that \p x and \p y may be dimension-incompatible boxes:
  in this case, the value <CODE>true</CODE> is returned.
*/
template <typename ITV>
bool operator!=(const Box<ITV>& x, const Box<ITV>& y);

namespace IO_Operators {

//! Output operator.
/*! \relates Parma_Polyhedra_Library::Box */
template <typename ITV>
std::ostream& operator<<(std::ostream& s, const Box<ITV>& box);

} // namespace IO_Operators

//! Computes the rectilinear (or Manhattan) distance between \p x and \p y.
/*! \relates Box
  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 ITV>
bool
rectilinear_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			    const Box<ITV>& x,
			    const Box<ITV>& y,
			    Rounding_Dir dir);

//! Computes the rectilinear (or Manhattan) distance between \p x and \p y.
/*! \relates Box
  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 ITV>
bool
rectilinear_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			    const Box<ITV>& x,
			    const Box<ITV>& y,
			    Rounding_Dir dir);

//! Computes the rectilinear (or Manhattan) distance between \p x and \p y.
/*! \relates Box
  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 ITV>
bool
rectilinear_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			    const Box<ITV>& x,
			    const Box<ITV>& y,
			    Rounding_Dir dir,
			    Temp& tmp0,
			    Temp& tmp1,
			    Temp& tmp2);

//! Computes the euclidean distance between \p x and \p y.
/*! \relates Box
  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 ITV>
bool
euclidean_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			  const Box<ITV>& x,
			  const Box<ITV>& y,
			  Rounding_Dir dir);

//! Computes the euclidean distance between \p x and \p y.
/*! \relates Box
  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 ITV>
bool
euclidean_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			  const Box<ITV>& x,
			  const Box<ITV>& y,
			  Rounding_Dir dir);

//! Computes the euclidean distance between \p x and \p y.
/*! \relates Box
  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 ITV>
bool
euclidean_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			  const Box<ITV>& x,
			  const Box<ITV>& y,
			  Rounding_Dir dir,
			  Temp& tmp0,
			  Temp& tmp1,
			  Temp& tmp2);

//! Computes the \f$L_\infty\f$ distance between \p x and \p y.
/*! \relates Box
  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 ITV>
bool
l_infinity_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			   const Box<ITV>& x,
			   const Box<ITV>& y,
			   Rounding_Dir dir);

//! Computes the \f$L_\infty\f$ distance between \p x and \p y.
/*! \relates Box
  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 ITV>
bool
l_infinity_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			   const Box<ITV>& x,
			   const Box<ITV>& y,
			   Rounding_Dir dir);

//! Computes the \f$L_\infty\f$ distance between \p x and \p y.
/*! \relates Box
  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 ITV>
bool
l_infinity_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			   const Box<ITV>& x,
			   const Box<ITV>& y,
			   Rounding_Dir dir,
			   Temp& tmp0,
			   Temp& tmp1,
			   Temp& tmp2);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \relates Box
  Helper function for computing distances.
*/
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename Specialization,
	  typename Temp, typename To, typename ITV>
bool
l_m_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
		    const Box<ITV>& x, const Box<ITV>& y,
		    Rounding_Dir dir,
		    Temp& tmp0, Temp& tmp1, Temp& tmp2);

} // namespace Parma_Polyhedra_Library

//! A not necessarily closed, iso-oriented hyperrectangle.
/*! \ingroup PPL_CXX_interface
  A Box object represents the smash product of \f$n\f$
  not necessarily closed and possibly unbounded intervals
  represented by objects of class \p ITV,
  where \f$n\f$ is the space dimension of the box.

  An <EM>interval constraint</EM> (resp., <EM>interval congruence</EM>)
  is a syntactic constraint (resp., congruence) that only mentions
  a single space dimension.

  The Box domain <EM>optimally supports</EM>:
    - tautological and inconsistent constraints and congruences;
    - the interval constraints that are optimally supported by
      the template argument class \c ITV;
    - the interval congruences that are optimally supported by
      the template argument class \c ITV.

  Depending on the method, using a constraint or congruence that is not
  optimally supported by the domain will either raise an exception or
  result in a (possibly non-optimal) upward approximation.

  The user interface for the Box domain is meant to be as similar
  as possible to the one developed for the polyhedron class C_Polyhedron.
*/
template <typename ITV>
class Parma_Polyhedra_Library::Box {
public:
  //! The type of intervals used to implement the box.
  typedef ITV interval_type;

  //! Returns the maximum space dimension that a Box can handle.
  static dimension_type max_space_dimension();

  /*! \brief
    Returns false indicating that this domain does not recycle constraints
  */
  static bool can_recycle_constraint_systems();

  /*! \brief
    Returns false indicating that this domain does not recycle congruences
  */
  static bool can_recycle_congruence_systems();

  //! \name Constructors, Assignment, Swap and Destructor
  //@{

  //! Builds a universe or empty box of the specified space dimension.
  /*!
    \param num_dimensions
    The number of dimensions of the vector space enclosing the box;

    \param kind
    Specifies whether the universe or the empty box has to be built.
  */
  explicit Box(dimension_type num_dimensions = 0,
	       Degenerate_Element kind = UNIVERSE);

  //! Ordinary copy-constructor.
  /*!
    The complexity argument is ignored.
  */
  Box(const Box& y,
      Complexity_Class complexity = ANY_COMPLEXITY);

  //! Builds a conservative, upward approximation of \p y.
  /*!
    The complexity argument is ignored.
  */
  template <typename Other_ITV>
  explicit Box(const Box<Other_ITV>& y,
               Complexity_Class complexity = ANY_COMPLEXITY);

  //! Builds a box from the system of constraints \p cs.
  /*!
    The box inherits the space dimension of \p cs.

    \param cs
    A system of constraints: constraints that are not
    \ref intervals "interval constraints"
    are ignored (even though they may have contributed
    to the space dimension).
  */
  explicit Box(const Constraint_System& cs);

  //! Builds a box recycling a system of constraints \p cs.
  /*!
    The box inherits the space dimension of \p cs.

    \param cs
    A system of constraints: constraints that are not
    \ref intervals "interval constraints"
    are ignored (even though they may have contributed
    to the space dimension).

    \param dummy
    A dummy tag to syntactically differentiate this one
    from the other constructors.
  */
  Box(const Constraint_System& cs, Recycle_Input dummy);

  //! Builds a box from the system of generators \p gs.
  /*!
    Builds the smallest box containing the polyhedron defined by \p gs.
    The box inherits the space dimension of \p gs.

    \exception std::invalid_argument
    Thrown if the system of generators is not empty but has no points.
  */
  explicit Box(const Generator_System& gs);

  //! Builds a box recycling the system of generators \p gs.
  /*!
    Builds the smallest box containing the polyhedron defined by \p gs.
    The box inherits the space dimension of \p gs.

    \param gs
    The generator system describing the polyhedron to be approximated.

    \param dummy
    A dummy tag to syntactically differentiate this one
    from the other constructors.

    \exception std::invalid_argument
    Thrown if the system of generators is not empty but has no points.
  */
  Box(const Generator_System& gs, Recycle_Input dummy);

  /*!
    Builds the smallest box containing the grid defined by a
    system of congruences \p cgs.
    The box inherits the space dimension of \p cgs.

    \param cgs
    A system of congruences: congruences that are not
    non-relational equality constraints are ignored
    (though they may have contributed to the space dimension).
  */
  explicit Box(const Congruence_System& cgs);

  /*!
    Builds the smallest box containing the grid defined by a
    system of congruences \p cgs, recycling \p cgs.
    The box inherits the space dimension of \p cgs.

    \param cgs
    A system of congruences: congruences that are not
    non-relational equality constraints are ignored
    (though they will contribute to the space dimension).

    \param dummy
    A dummy tag to syntactically differentiate this one
    from the other constructors.
  */
  Box(const Congruence_System& cgs, Recycle_Input dummy);

  //! Builds a box containing the BDS \p bds.
  /*!
    Builds the smallest box containing \p bds using a polynomial algorithm.
    The \p complexity argument is ignored.
  */
  template <typename T>
  explicit Box(const BD_Shape<T>& bds,
	       Complexity_Class complexity = POLYNOMIAL_COMPLEXITY);

  //! Builds a box containing the octagonal shape \p oct.
  /*!
    Builds the smallest box containing \p oct using a polynomial algorithm.
    The \p complexity argument is ignored.
  */
  template <typename T>
  explicit Box(const Octagonal_Shape<T>& oct,
	       Complexity_Class complexity = POLYNOMIAL_COMPLEXITY);

  //! Builds a box containing the polyhedron \p ph.
  /*!
    Builds a box 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 built box is the
    smallest one containing \p ph.
  */
  explicit Box(const Polyhedron& ph,
	       Complexity_Class complexity = ANY_COMPLEXITY);

  //! Builds a box containing the grid \p gr.
  /*!
    Builds the smallest box containing \p gr using a polynomial algorithm.
    The \p complexity argument is ignored.
  */
  explicit Box(const Grid& ph,
	       Complexity_Class complexity = POLYNOMIAL_COMPLEXITY);

  //! Builds a box containing the partially reduced product \p dp.
  /*!
    Builds a box containing \p ph using algorithms whose complexity
    does not exceed the one specified by \p complexity.
  */
  template <typename D1, typename D2, typename R>
  explicit Box(const Partially_Reduced_Product<D1, D2, R>& dp,
	       Complexity_Class complexity = ANY_COMPLEXITY);

  /*! \brief
    The assignment operator
    (\p *this and \p y can be dimension-incompatible).
  */
  Box& operator=(const Box& y);

  /*! \brief
    Swaps \p *this with \p y
    (\p *this and \p y can be dimension-incompatible).
  */
  void swap(Box& y);

  //@} Constructors, Assignment, Swap and Destructor

  //! \name Member Functions that Do Not Modify the Box
  //@{

  //! 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 <CODE>true</CODE> if and only if \p *this is an empty box.
  bool is_empty() const;

  //! Returns <CODE>true</CODE> if and only if \p *this is a universe box.
  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 is discrete.
  bool is_discrete() const;

  //! Returns <CODE>true</CODE> if and only if \p *this is a bounded box.
  bool is_bounded() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this
    contains at least one integer point.
  */
  bool contains_integer_point() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p var is constrained in
    \p *this.

    \exception std::invalid_argument
    Thrown if \p var is not a space dimension of \p *this.
  */
  bool constrains(Variable var) 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.
  */
  Poly_Con_Relation relation_with(const Constraint& c) const;

  //! Returns the relations holding between \p *this and the congruence \p cg.
  /*!
    \exception std::invalid_argument
    Thrown if \p *this and constraint \p cg are dimension-incompatible.
  */
  Poly_Con_Relation relation_with(const Congruence& cg) 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;

  /*! \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 g
    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 g are left untouched.
  */
  bool maximize(const Linear_Expression& expr,
		Coefficient& sup_n, Coefficient& sup_d, bool& maximum,
		Generator& g) 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 g
    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 g are left untouched.
  */
  bool minimize(const Linear_Expression& expr,
		Coefficient& inf_n, Coefficient& inf_d, bool& minimum,
		Generator& g) const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this contains \p y.

    \exception std::invalid_argument
    Thrown if \p x and \p y are dimension-incompatible.
  */
  bool contains(const Box&) const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this strictly contains \p y.

    \exception std::invalid_argument
    Thrown if \p x and \p y are dimension-incompatible.
  */
  bool strictly_contains(const Box&) 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 Box& y) 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 Box

  //! \name Space-Dimension Preserving Member Functions that May Modify the Box
  //@{

  /*! \brief
    Adds a copy of constraint \p c to the system of constraints
    defining \p *this.

    \param c
    The constraint to be added.

    \exception std::invalid_argument
    Thrown if \p *this and constraint \p c are dimension-incompatible,
    or \p c is not optimally supported by the Box domain.
  */
  void add_constraint(const Constraint& c);

  /*! \brief
    Adds the constraints in \p cs to the system of constraints
    defining \p *this.

    \param  cs
    The constraints to be added.

    \exception std::invalid_argument
    Thrown if \p *this and \p cs are dimension-incompatible,
    or \p cs contains a constraint which is not optimally supported
    by the box domain.
  */
  void add_constraints(const Constraint_System& cs);

  /*! \brief
    Adds the constraints in \p cs to the system of constraints
    defining \p *this.

    \param  cs
    The constraints to be added. They may be recycled.

    \exception std::invalid_argument
    Thrown if \p *this and \p cs are dimension-incompatible,
    or \p cs contains a constraint which is not optimally supported
    by the box domain.

    \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 to \p *this a constraint equivalent to the congruence \p cg.

    \param cg
    The congruence to be added.

    \exception std::invalid_argument
    Thrown if \p *this and congruence \p cg are dimension-incompatible,
    or \p cg is not optimally supported by the box domain.
  */
  void add_congruence(const Congruence& cg);

  /*! \brief
    Adds to \p *this constraints equivalent to the congruences in \p cgs.

    \param cgs
    The congruences to be added.

    \exception std::invalid_argument
    Thrown if \p *this and \p cgs are dimension-incompatible,
    or \p cgs contains a congruence which is not optimally supported
    by the box domain.
  */
  void add_congruences(const Congruence_System& cgs);

  /*! \brief
    Adds to \p *this constraints equivalent to the congruences in \p cgs.

    \param cgs
    The congruence system to be added to \p *this.  The congruences in
    \p cgs may be recycled.

    \exception std::invalid_argument
    Thrown if \p *this and \p cgs are dimension-incompatible,
    or \p cgs contains a congruence which is not optimally supported
    by the box domain.

    \warning
    The only assumption that can be made on \p cgs upon successful or
    exceptional return is that it can be safely destroyed.
  */
  void add_recycled_congruences(Congruence_System& cgs);

  /*! \brief
    Use the constraint \p c to refine \p *this.

    \param c
    The constraint to be used for refinement.

    \exception std::invalid_argument
    Thrown if \p *this and \p c are dimension-incompatible.
  */
  void refine_with_constraint(const Constraint& c);

  /*! \brief
    Use the constraints in \p cs to refine \p *this.

    \param  cs
     The constraints to be used for refinement.

     \exception std::invalid_argument
     Thrown if \p *this and \p cs are dimension-incompatible.
  */
  void refine_with_constraints(const Constraint_System& cs);

  /*! \brief
    Use the congruence \p cg to refine \p *this.

    \param cg
    The congruence to be used for refinement.

    \exception std::invalid_argument
    Thrown if \p *this and \p cg are dimension-incompatible.
  */
  void refine_with_congruence(const Congruence& cg);

  /*! \brief
    Use the congruences in \p cgs to refine \p *this.

    \param  cgs
    The congruences to be used for refinement.

    \exception std::invalid_argument
    Thrown if \p *this and \p cgs are dimension-incompatible.
  */
  void refine_with_congruences(const Congruence_System& cgs);

  /*! \brief
    Use the constraint \p c for constraint propagation on \p *this.

    \param c
    The constraint to be used for constraint propagation.

    \exception std::invalid_argument
    Thrown if \p *this and \p c are dimension-incompatible.
  */
  void propagate_constraint(const Constraint& c);

  /*! \brief
    Use the constraints in \p cs for constraint propagagion on \p *this.

    \param  cs
     The constraints to be used for constraint propagation.

     \exception std::invalid_argument
     Thrown if \p *this and \p cs are dimension-incompatible.
  */
  void propagate_constraints(const Constraint_System& cs);

  /*! \brief
    Computes the \ref Cylindrification "cylindrification" of \p *this with
    respect to space dimension \p var, assigning the result to \p *this.

    \param var
    The space dimension that will be unconstrained.

    \exception std::invalid_argument
    Thrown if \p var is not a space dimension of \p *this.
  */
  void unconstrain(Variable var);

  /*! \brief
    Computes the \ref Cylindrification "cylindrification" of \p *this with
    respect to the set of space dimensions \p to_be_unconstrained,
    assigning the result to \p *this.

    \param to_be_unconstrained
    The set of space dimension that will be unconstrained.

    \exception std::invalid_argument
    Thrown if \p *this is dimension-incompatible with one of the
    Variable objects contained in \p to_be_removed.
  */
  void unconstrain(const Variables_Set& to_be_unconstrained);

  //! 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 Box& y);

  /*! \brief
    Assigns to \p *this the smallest box containing the union
    of \p *this and \p y.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are dimension-incompatible.
  */
  void upper_bound_assign(const Box& y);

  /*! \brief
    If the upper bound 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 upper_bound_assign_if_exact(const Box& y);

  /*! \brief
    Assigns to \p *this the difference of \p *this and \p y.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are dimension-incompatible.
  */
  void difference_assign(const Box& y);

  /*! \brief
    Assigns to \p *this a \ref Meet_Preserving_Simplification
    "meet-preserving simplification" of \p *this with respect to \p y.
    If \c false is returned, then the intersection is empty.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are dimension-incompatible.
  */
  bool simplify_using_context_assign(const Box& 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.
  */
  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.
  */
  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.
  */
  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 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.
  */
  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 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.
  */
  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 "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.
  */
  void generalized_affine_preimage(const Linear_Expression& lhs,
				   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 dimension-incompatible.
  */
  void time_elapse_assign(const Box& y);

  //! Assigns to \p *this its topological closure.
  void topological_closure_assign();

  /*! \brief
    Assigns to \p *this the result of computing the
    \ref CC76_extrapolation "CC76-widening" between \p *this and \p y.

    \param y
    A box 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_widening_assign(const Box& y, unsigned* tp = 0);

  /*! \brief
    Assigns to \p *this the result of computing the
    \ref CC76_extrapolation "CC76-widening" between \p *this and \p y.

    \param y
    A 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 Box& y,
			    Iterator first, Iterator last);

  //! Same as CC76_widening_assign(y, tp).
  void widening_assign(const Box& y, unsigned* tp = 0);

  /*! \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 box that <EM>must</EM> be contained in \p *this.

    \param cs
    The system of constraints used to improve the widened box.

    \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 Box& 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 Box 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>decreasing</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 Box& y);

  //@} 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 box 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
    box, which is defined by a system of interval constraints in which the
    variables running through the new dimensions are unconstrained.
    For instance, when starting from the box \f$\cB \sseq \Rset^2\f$
    and adding a third dimension, the result will be the box
    \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 box 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 box, 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 box \f$\cB \sseq \Rset^2\f$
    and adding a third dimension, the result will be the box
    \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 box 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 boxes
    corresponding, on entry, to \p *this and \p y, respectively.
    Upon successful completion, \p *this will represent the box
    \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 Box& 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 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 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 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

  /*! \brief
    Returns a reference the interval that bounds \p var.

    \exception std::invalid_argument
    Thrown if \p var is not a space dimension of \p *this.
  */
  const ITV& get_interval(Variable var) const;

  /*! \brief
    Sets to \p i the interval that bounds \p var.

    \exception std::invalid_argument
    Thrown if \p var is not a space dimension of \p *this.
  */
  void set_interval(Variable var, const ITV& i);

  /*! \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;

  //! 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 a system of congruences approximating \p *this.
  Congruence_System congruences() const;

  //! Returns a minimized system of congruences approximating \p *this.
  Congruence_System minimized_congruences() 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;

  PPL_OUTPUT_DECLARATIONS

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  /*! \brief
    Loads from \p s an ASCII representation (as produced by
    ascii_dump(std::ostream&) const) and sets \p *this accordingly.
    Returns <CODE>true</CODE> if successful, <CODE>false</CODE> otherwise.
  */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
  bool ascii_load(std::istream& s);

private:
  template <typename Other_ITV>
  friend class Parma_Polyhedra_Library::Box;

  friend bool
  operator==<ITV>(const Box<ITV>& x, const Box<ITV>& y);

  friend std::ostream&
  Parma_Polyhedra_Library
  ::IO_Operators::operator<<<>(std::ostream& s, const Box<ITV>& box);

  template <typename Specialization, typename Temp, typename To, typename I>
  friend bool Parma_Polyhedra_Library::l_m_distance_assign
  (Checked_Number<To, Extended_Number_Policy>& r,
   const Box<I>& x, const Box<I>& y, const Rounding_Dir dir,
   Temp& tmp0, Temp& tmp1, Temp& tmp2);

  //! The type of sequence used to implement the box.
  typedef std::vector<ITV> Sequence;

  /*! \brief
    The type of intervals used by inner computations when trying to limit
    the cumulative effect of approximation errors.
  */
  typedef ITV Tmp_Interval_Type;

  //! A sequence of intervals, one for each dimension of the vector space.
  Sequence seq;

#define PPL_IN_Box_CLASS
/* Automatically generated from PPL source file ../src/Box_Status.idefs.hh line 1. */
/* Box<ITV>::Status class declaration.
*/


#ifndef PPL_IN_Box_CLASS
#error "Do not include Box_Status.idefs.hh directly; use Box.defs.hh instead."
#endif

//! A conjunctive assertion about a Box<ITV> object.
/*! \ingroup PPL_CXX_interface
  The assertions supported are:
  - <EM>empty up-to-date</EM>: the empty flag is meaningful;
  - <EM>empty</EM>: the box is the empty set.
  - <EM>universe</EM>: the box is universe \f$n\f$-dimensional vector space
     \f$\Rset^n\f$.

  Not all the conjunctions of these elementary assertions constitute
  a legal Status.  In fact:
  - <EM>empty up-to-date</EM> and <EM>empty</EM> excludes <EM>universe</EM>.
*/
class Status;

class Status {
public:
  //! By default Status is the empty set of assertion.
  Status();

  //! Ordinary copy-constructor.
  Status(const Status& y);

  //! Copy-constructor from a box of different type.
  template <typename Other_ITV>
  Status(const typename Box<Other_ITV>::Status& y);

  //! \name Test, remove or add an individual assertion from the conjunction.
  //@{
  bool test_empty_up_to_date() const;
  void reset_empty_up_to_date();
  void set_empty_up_to_date();

  bool test_empty() const;
  void reset_empty();
  void set_empty();

  bool test_universe() const;
  void reset_universe();
  void set_universe();
  //@}

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

  PPL_OUTPUT_DECLARATIONS

  /*! \brief
    Loads from \p s an ASCII representation (as produced by
    ascii_dump(std::ostream&) const) 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 NONE             = 0U;
  static const flags_t EMPTY_UP_TO_DATE = 1U << 0;
  static const flags_t EMPTY            = 1U << 1;
  static const flags_t UNIVERSE         = 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/Box.defs.hh line 1559. */
#undef PPL_IN_Box_CLASS

  //! The status flags to keep track of the internal state.
  Status status;

  /*! \brief
    Returns <CODE>true</CODE> if and only if the box 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;

public:
  //! Causes the box to become empty, i.e., to represent the empty set.
  void set_empty();

private:
  //! Marks \p *this as definitely not empty.
  void set_nonempty();

  //! Asserts the validity of the empty flag of \p *this.
  void set_empty_up_to_date();

  //! Invalidates empty flag of \p *this.
  void reset_empty_up_to_date();

  /*! \brief
    Checks the hard way whether \p *this is an empty box:
    returns <CODE>true</CODE> if and only if it is so.
  */
  bool check_empty() const;

   /*! \brief
     Returns a reference the interval that bounds
     the box on the <CODE>k</CODE>-th space dimension.
   */
  const ITV& operator[](dimension_type k) const;

  /*! \brief
    WRITE ME.
  */
  void
  add_interval_constraint_no_check(dimension_type var_id,
                                   Constraint::Type type,
                                   Coefficient_traits::const_reference num,
                                   Coefficient_traits::const_reference den);

  /*! \brief
    WRITE ME.
  */
  void add_constraint_no_check(const Constraint& c);

  /*! \brief
    WRITE ME.
  */
  void add_constraints_no_check(const Constraint_System& cs);

  /*! \brief
    WRITE ME.
  */
  void add_congruence_no_check(const Congruence& cg);

  /*! \brief
    WRITE ME.
  */
  void add_congruences_no_check(const Congruence_System& cgs);

  /*! \brief
    Uses the constraint \p c to refine \p *this.

    \param c
    The constraint to be added.
    Non-interval constraints are ignored.

    \warning
    If \p c and \p *this are dimension-incompatible,
    the behavior is undefined.
  */
  void refine_no_check(const Constraint& c);

  /*! \brief
    Uses the constraints in \p cs to refine \p *this.

    \param cs
    The constraints to be added.
    Non-interval constraints are ignored.

    \warning
    If \p cs and \p *this are dimension-incompatible,
    the behavior is undefined.
  */
  void refine_no_check(const Constraint_System& cs);

  /*! \brief
    Uses the congruence \p cg to refine \p *this.

    \param cg
    The congruence to be added.
    Nontrivial proper congruences are ignored.

    \warning
    If \p cg and \p *this are dimension-incompatible,
    the behavior is undefined.
  */
  void refine_no_check(const Congruence& cg);

  /*! \brief
    Uses the congruences in \p cgs to refine \p *this.

    \param cgs
    The congruences to be added.
    Nontrivial proper congruences are ignored.

    \warning
    If \p cgs and \p *this are dimension-incompatible,
    the behavior is undefined.
  */
  void refine_no_check(const Congruence_System& cgs);

  /*! \brief
    Propagates the constraint \p c to refine \p *this.

    \param c
    The constraint to be propagated.

    \warning
    If \p c and \p *this are dimension-incompatible,
    the behavior is undefined.

    \warning
    This method may lead to non-termination.

    \if Include_Implementation_Details

    For any expression \f$e\f$, we denote by
    \f$\left\uparrow e \right\uparrow\f$ (resp., \f$\left\downarrow e
    \right\downarrow\f$) the result of any computation that is
    guaranteed to yield an upper (resp., lower) approximation of
    \f$e\f$.  So there exists \f$\epsilon \in \Rset\f$ with
    \f$\epsilon \geq 0\f$ such that
    \f$\left\uparrow e \right\uparrow = e + \epsilon\f$.
    If \f$\epsilon = 0\f$ we say that the computation of
    \f$\left\uparrow e \right\uparrow\f$ is <EM>exact</EM>;
    we say it is <EM>inexact</EM> otherwise.
    Similarly for \f$\left\downarrow e \right\downarrow\f$.

    Consider a constraint of the general form
    \f[
      z + \sum_{i \in I}{a_ix_i} \relsym 0,
    \f]
    where \f$z \in \Zset\f$, \f$I\f$ is a set of indices,
    \f$a_i \in \Zset\f$ with \f$a_i \neq 0\f$ for each \f$i \in I\f$, and
    \f$\mathord{\relsym} \in \{ \mathord{\geq}, \mathord{>}, \mathord{=} \}\f$.
    The set \f$I\f$ is subdivided into the disjoint sets \f$P\f$ and \f$N\f$
    such that, for each \f$i \in I\f$, \f$a_i > 0\f$ if \f$i \in P\f$ and
    \f$a_i < 0\f$ if \f$i \in N\f$.
    Suppose that, for each \f$i \in P \union N\f$ a variation interval
    \f$\chi_i \sseq \Rset\f$ is known for \f$x_i\f$ and that the infimum
    and the supremum of \f$\chi_i\f$ are denoted, respectively,
    by \f$\chi_i^\mathrm{l}\f$ and \f$\chi_i^\mathrm{u}\f$, where
    \f$\chi_i^\mathrm{l}, \chi_i^\mathrm{u} \in \Rset \union \{ -\infty, +\infty \}\f$.

    For each \f$k \in P\f$, we have
    \f[
      x_k
        \relsym
          \frac{1}{a_k}
            \Biggl(
              - z
              - \sum_{i \in N}{a_ix_i}
              - \sum_{\genfrac{}{}{0pt}{}
                              {\scriptstyle i \in P}
                              {\scriptstyle i \neq k}}{a_ix_i}
            \Biggr).
    \f]
    Thus, if \f$\chi_i^\mathrm{l} \in \Rset\f$ for each \f$i \in N\f$ and
    \f$\chi_i^\mathrm{u} \in \Rset\f$ for each \f$i \in P \setdiff \{ k \}\f$,
    we have
    \f[
      x_k
        \geq
          \Biggl\downarrow
          \frac{1}{a_k}
            \Biggl(
              - z
              - \sum_{i \in N}{a_i\chi_i^\mathrm{l}}
              - \sum_{\genfrac{}{}{0pt}{}
                              {\scriptstyle i \in P}
                              {\scriptstyle i \neq k}}{a_i\chi_i^\mathrm{u}}
            \Biggr)
          \Biggr\downarrow
    \f]
    and, if \f$\mathord{\relsym} \in \{ \mathord{=} \}\f$,
    \f$\chi_i^\mathrm{u} \in \Rset\f$ for each \f$i \in N\f$ and
    \f$\chi_i^\mathrm{l} \in \Rset\f$ for each \f$P \setdiff \{ k \}\f$,
    \f[
      x_k
        \leq
          \Biggl\uparrow
          \frac{1}{a_k}
            \Biggl(
              - z
              - \sum_{i \in N}{a_i\chi_i^\mathrm{u}}
              - \sum_{\genfrac{}{}{0pt}{}
                              {\scriptstyle i \in P}
                              {\scriptstyle i \neq k}}{a_i\chi_i^\mathrm{l}}
            \Biggr)
          \Biggl\uparrow.
    \f]
    In the first inequality, the relation is strict if
    \f$\mathord{\relsym} \in \{ \mathord{>} \}\f$, or if
    \f$\chi_i^\mathrm{l} \notin \chi_i\f$ for some \f$i \in N\f$, or if
    \f$\chi_i^\mathrm{u} \notin \chi_i\f$ for some
    \f$i \in P \setdiff \{ k \}\f$, or if the computation is inexact.
    In the second inequality, the relation is strict if
    \f$\chi_i^\mathrm{u} \notin \chi_i\f$ for some \f$i \in N\f$, or if
    \f$\chi_i^\mathrm{l} \notin \chi_i\f$ for some
    \f$i \in P \setdiff \{ k \}\f$, or if the computation is inexact.

    For each \f$k \in N\f$, we have
    \f[
      \frac{1}{a_k}
        \Biggl(
          - z
          - \sum_{\genfrac{}{}{0pt}{}
                          {\scriptstyle i \in N}
                          {\scriptstyle i \neq k}}{a_ix_i}
          - \sum_{i \in P}{a_ix_i}
        \Biggr)
          \relsym
            x_k.
    \f]
    Thus, if
    \f$\chi_i^\mathrm{l} \in \Rset\f$
    for each \f$i \in N \setdiff \{ k \}\f$ and
    \f$\chi_i^\mathrm{u} \in \Rset\f$ for each \f$i \in P\f$,
    we have
    \f[
      \Biggl\uparrow
      \frac{1}{a_k}
        \Biggl(
          - z
          - \sum_{\genfrac{}{}{0pt}{}
                          {\scriptstyle i \in N}
                          {\scriptstyle i \neq k}}{a_i\chi_i^\mathrm{l}}
          - \sum_{i \in P}{a_i\chi_i^\mathrm{u}}
        \Biggr)
      \Biggl\uparrow
        \geq
          x_k
    \f]
    and, if \f$\mathord{\relsym} \in \{ \mathord{=} \}\f$,
    \f$\chi_i^\mathrm{u} \in \Rset\f$ for each \f$i \in N \setdiff \{ k \}\f$
    and \f$\chi_i^\mathrm{l} \in \Rset\f$ for each \f$i \in P\f$,
    \f[
      \Biggl\downarrow
      \frac{1}{a_k}
        \Biggl(
          - z
          - \sum_{\genfrac{}{}{0pt}{}
                          {\scriptstyle i \in N}
                          {\scriptstyle i \neq k}}{a_i\chi_i^\mathrm{u}}
          - \sum_{i \in P}{a_i\chi_i^\mathrm{l}}
        \Biggr)
      \Biggl\downarrow
        \leq
          x_k.
    \f]
    In the first inequality, the relation is strict if
    \f$\mathord{\relsym} \in \{ \mathord{>} \}\f$, or if
    \f$\chi_i^\mathrm{u} \notin \chi_i\f$ for some \f$i \in P\f$, or if
    \f$\chi_i^\mathrm{l} \notin \chi_i\f$ for some
    \f$i \in N \setdiff \{ k \}\f$, or if the computation is inexact.
    In the second inequality, the relation is strict if
    \f$\chi_i^\mathrm{l} \notin \chi_i\f$ for some \f$i \in P\f$, or if
    \f$\chi_i^\mathrm{u} \notin \chi_i\f$ for some
    \f$i \in N \setdiff \{ k \}\f$, or if the computation is inexact.
    \endif
  */
  void propagate_constraint_no_check(const Constraint& c);

  /*! \brief
    Propagates the constraints in \p cs to refine \p *this.

    \param  cs
    The constraints to be propagated.

    \warning
    If \p cs and \p *this are dimension-incompatible,
    the behavior is undefined.

    \warning
    This method may lead to non-termination.
  */
  void propagate_constraints_no_check(const Constraint_System& cs);

  //! 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 g
    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 g are left untouched.
  */
  bool max_min(const Linear_Expression& expr,
	       bool maximize,
	       Coefficient& ext_n, Coefficient& ext_d, bool& included,
	       Generator& g) 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;

    \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,
	       bool maximize,
	       Coefficient& ext_n, Coefficient& ext_d, bool& included) const;

  /*! \brief
    Adds to \p limiting_box the interval constraints in \p cs
    that are satisfied by \p *this.
  */
  void get_limiting_box(const Constraint_System& cs,
                        Box& limiting_box) const;

  //! \name Exception Throwers
  //@{
  void throw_dimension_incompatible(const char* method,
				    const Box& 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 Congruence& cg) const;

  void throw_dimension_incompatible(const char* method,
				    const Constraint_System& cs) const;

  void throw_dimension_incompatible(const char* method,
				    const Congruence_System& cgs) 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_space_dimension_overflow(const char* method,
					     const char* reason);

  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 Parma_Polyhedra_Library {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \brief
  Returns the relations holding between an interval and
  an interval constraint.

  \param i
  The interval;

  \param constraint_type
  The constraint type;

  \param num
  The numerator of the constraint bound;

  \param den
  The denominator of the constraint bound

  The interval constraint has the form
  <CODE>den * Variable(0) relsym num</CODE>
  where relsym is  <CODE>==</CODE>,  <CODE>></CODE> or  <CODE>>=</CODE>
  depending on the <CODE>constraint_type</CODE>.
*/
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename ITV>
Poly_Con_Relation
interval_relation(const ITV& i,
                  const Constraint::Type constraint_type,
                  Coefficient_traits::const_reference num,
                  Coefficient_traits::const_reference den = 1);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Decodes the constraint \p c as an interval constraint.
/*! \relates Box
  \return
  <CODE>true</CODE> if the constraint \p c is an
  \ref intervals "interval constraint";
  <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 and 1.

  \param c_only_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 only variable having
  a non-zero coefficient in \p c.
*/
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
bool extract_interval_constraint(const Constraint& c,
				 dimension_type c_space_dim,
				 dimension_type& c_num_vars,
				 dimension_type& c_only_var);

bool extract_interval_congruence(const Congruence& cg,
				 dimension_type cg_space_dim,
				 dimension_type& cg_num_vars,
				 dimension_type& cg_only_var);

} // namespace Parma_Polyhedra_Library

/* Automatically generated from PPL source file ../src/Box_Status.inlines.hh line 1. */
/* Box<ITV>::Status class implementation: inline functions.
*/


#include <string>

namespace Parma_Polyhedra_Library {

template <typename ITV>
inline
Box<ITV>::Status::Status(flags_t mask)
  : flags(mask) {
}

template <typename ITV>
inline
Box<ITV>::Status::Status(const Status& y)
  : flags(y.flags) {
}

template <typename ITV>
template <typename Other_ITV>
inline
Box<ITV>::Status::Status(const typename Box<Other_ITV>::Status& y)
  : flags(y.flags) {
}

template <typename ITV>
inline
Box<ITV>::Status::Status()
  : flags(NONE) {
}

template <typename ITV>
inline bool
Box<ITV>::Status::test_all(flags_t mask) const {
  return (flags & mask) == mask;
}

template <typename ITV>
inline bool
Box<ITV>::Status::test_any(flags_t mask) const {
  return flags & mask;
}

template <typename ITV>
inline void
Box<ITV>::Status::set(flags_t mask) {
  flags |= mask;
}

template <typename ITV>
inline void
Box<ITV>::Status::reset(flags_t mask) {
  flags &= ~mask;
}

template <typename ITV>
inline bool
Box<ITV>::Status::test_empty_up_to_date() const {
  return test_any(EMPTY_UP_TO_DATE);
}

template <typename ITV>
inline void
Box<ITV>::Status::reset_empty_up_to_date() {
  reset(EMPTY_UP_TO_DATE);
}

template <typename ITV>
inline void
Box<ITV>::Status::set_empty_up_to_date() {
  set(EMPTY_UP_TO_DATE);
}

template <typename ITV>
inline bool
Box<ITV>::Status::test_empty() const {
  return test_any(EMPTY);
}

template <typename ITV>
inline void
Box<ITV>::Status::reset_empty() {
  reset(EMPTY);
}

template <typename ITV>
inline void
Box<ITV>::Status::set_empty() {
  set(EMPTY);
}

template <typename ITV>
inline bool
Box<ITV>::Status::test_universe() const {
  return test_any(UNIVERSE);
}

template <typename ITV>
inline void
Box<ITV>::Status::reset_universe() {
  reset(UNIVERSE);
}

template <typename ITV>
inline void
Box<ITV>::Status::set_universe() {
  set(UNIVERSE);
}

template <typename ITV>
bool
Box<ITV>::Status::OK() const {
  if (test_empty_up_to_date()
      && test_empty()
      && test_universe()) {
#ifndef NDEBUG
    std::cerr
      << "The status asserts emptiness and universality at the same time."
      << std::endl;
#endif
    return false;
  }

  // Any other case is OK.
  return true;
}


namespace Implementation {

namespace Boxes {

// These are the keywords that indicate the individual assertions.
const std::string empty_up_to_date = "EUP";
const std::string empty = "EM";
const std::string universe = "UN";
const char yes = '+';
const char no = '-';
const char sep = ' ';

/*! \relates Parma_Polyhedra_Library::Box::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 Boxes

} // namespace Implementation

template <typename ITV>
void
Box<ITV>::Status::ascii_dump(std::ostream& s) const {
  using namespace Implementation::Boxes;
  s << (test_empty_up_to_date() ? yes : no) << empty_up_to_date << sep
    << (test_empty() ? yes : no) << empty << sep
    << (test_universe() ? yes : no) << universe << sep;
}

PPL_OUTPUT_TEMPLATE_DEFINITIONS_ASCII_ONLY(ITV, Box<ITV>::Status)

template <typename ITV>
bool
Box<ITV>::Status::ascii_load(std::istream& s) {
  using namespace Implementation::Boxes;
  PPL_UNINITIALIZED(bool, positive);

  if (!get_field(s, Implementation::Boxes::empty_up_to_date, positive))
    return false;
  if (positive)
    set_empty_up_to_date();

  if (!get_field(s, Implementation::Boxes::empty, positive))
    return false;
  if (positive)
    set_empty();

  if (!get_field(s, universe, positive))
    return false;
  if (positive)
    set_universe();
  else
    reset_universe();

  // Check invariants.
  assert(OK());
  return true;
}

} // namespace Parma_Polyhedra_Library

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


/* Automatically generated from PPL source file ../src/Box.inlines.hh line 32. */

namespace Parma_Polyhedra_Library {

template <typename ITV>
inline bool
Box<ITV>::marked_empty() const {
  return status.test_empty_up_to_date() && status.test_empty();
}

template <typename ITV>
inline void
Box<ITV>::set_empty() {
  status.set_empty();
  status.set_empty_up_to_date();
}

template <typename ITV>
inline void
Box<ITV>::set_nonempty() {
  status.reset_empty();
  status.set_empty_up_to_date();
}

template <typename ITV>
inline void
Box<ITV>::set_empty_up_to_date() {
  status.set_empty_up_to_date();
}

template <typename ITV>
inline void
Box<ITV>::reset_empty_up_to_date() {
  return status.reset_empty_up_to_date();
}

template <typename ITV>
inline
Box<ITV>::Box(const Box& y, Complexity_Class)
  : seq(y.seq), status(y.status) {
}

template <typename ITV>
inline Box<ITV>&
Box<ITV>::operator=(const Box& y) {
  seq = y.seq;
  status = y.status;
  return *this;
}

template <typename ITV>
inline void
Box<ITV>::swap(Box& y) {
  Box& x = *this;
  std::swap(x.seq, y.seq);
  std::swap(x.status, y.status);
}

template <typename ITV>
inline
Box<ITV>::Box(const Constraint_System& cs, Recycle_Input) {
  // Recycling is useless: just delegate.
  Box<ITV> tmp(cs);
  this->swap(tmp);
}

template <typename ITV>
inline
Box<ITV>::Box(const Generator_System& gs, Recycle_Input) {
  // Recycling is useless: just delegate.
  Box<ITV> tmp(gs);
  this->swap(tmp);
}

template <typename ITV>
inline
Box<ITV>::Box(const Congruence_System& cgs, Recycle_Input) {
  // Recycling is useless: just delegate.
  Box<ITV> tmp(cgs);
  this->swap(tmp);
}

template <typename ITV>
inline memory_size_type
Box<ITV>::total_memory_in_bytes() const {
  return sizeof(*this) + external_memory_in_bytes();
}

template <typename ITV>
inline dimension_type
Box<ITV>::space_dimension() const {
  return seq.size();
}

template <typename ITV>
inline dimension_type
Box<ITV>::max_space_dimension() {
  // One dimension is reserved to have a value of type dimension_type
  // that does not represent a legal dimension.
  return Sequence().max_size() - 1;
}

template <typename ITV>
inline const ITV&
Box<ITV>::operator[](const dimension_type k) const {
  assert(k < seq.size());
  return seq[k];
}

template <typename ITV>
inline const ITV&
Box<ITV>::get_interval(const Variable var) const {
  if (space_dimension() < var.space_dimension())
    throw_dimension_incompatible("get_interval(v)", "v", var);

  if (is_empty()) {
    static ITV empty_interval(EMPTY);
    return empty_interval;
  }

  return seq[var.id()];
}

template <typename ITV>
inline void
Box<ITV>::set_interval(const Variable var, const ITV& i) {
  const dimension_type space_dim = space_dimension();
  if (space_dim < var.space_dimension())
    throw_dimension_incompatible("set_interval(v, i)", "v", var);

  if (is_empty() && space_dim >= 2)
    // If the box is empty, and has dimension >= 2, setting only one
    // interval will not make it non-empty.
    return;

  seq[var.id()] = i;
  reset_empty_up_to_date();

  assert(OK());
}

template <typename ITV>
inline bool
Box<ITV>::is_empty() const {
  return marked_empty() || check_empty();
}

template <typename ITV>
inline bool
Box<ITV>::bounds_from_above(const Linear_Expression& expr) const {
  return bounds(expr, true);
}

template <typename ITV>
inline bool
Box<ITV>::bounds_from_below(const Linear_Expression& expr) const {
  return bounds(expr, false);
}

template <typename ITV>
inline bool
Box<ITV>::maximize(const Linear_Expression& expr,
                   Coefficient& sup_n, Coefficient& sup_d,
                   bool& maximum) const {
  return max_min(expr, true, sup_n, sup_d, maximum);
}

template <typename ITV>
inline bool
Box<ITV>::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);
}

template <typename ITV>
inline bool
Box<ITV>::minimize(const Linear_Expression& expr,
                   Coefficient& inf_n, Coefficient& inf_d,
                   bool& minimum) const {
  return max_min(expr, false, inf_n, inf_d, minimum);
}

template <typename ITV>
inline bool
Box<ITV>::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);
}

template <typename ITV>
inline bool
Box<ITV>::strictly_contains(const Box& y) const {
  const Box& x = *this;
  return x.contains(y) && !y.contains(x);
}

template <typename ITV>
inline void
Box<ITV>::expand_space_dimension(const Variable var,
                                 const dimension_type m) {
  const dimension_type space_dim = space_dimension();
  // `var' should be one of the dimensions of the vector space.
  if (var.space_dimension() > space_dim)
    throw_dimension_incompatible("expand_space_dimension(v, m)", "v", var);

  // The space dimension of the resulting Box should not
  // overflow the maximum allowed space dimension.
  if (m > max_space_dimension() - space_dim)
    throw_generic("expand_dimension(v, m)",
		  "adding m new space dimensions exceeds "
		  "the maximum allowed space dimension");

  // To expand the space dimension corresponding to variable `var',
  // we append to the box `m' copies of the corresponding interval.
  seq.insert(seq.end(), m, seq[var.id()]);
  assert(OK());
}

template <typename ITV>
inline bool
operator!=(const Box<ITV>& x, const Box<ITV>& y) {
  return !(x == y);
}

template <typename ITV>
inline bool
Box<ITV>::get_lower_bound(const dimension_type k, bool& closed,
                          Coefficient& n, Coefficient& d) const {
  assert(k < seq.size());
  const ITV& seq_k = seq[k];

  if (seq_k.lower_is_unbounded())
    return false;

  closed = !seq_k.lower_is_open();

  PPL_DIRTY_TEMP0(mpq_class, lr);
  assign_r(lr, seq_k.lower(), ROUND_NOT_NEEDED);
  n = lr.get_num();
  d = lr.get_den();

  return true;
}

template <typename ITV>
inline bool
Box<ITV>::get_upper_bound(const dimension_type k, bool& closed,
                          Coefficient& n, Coefficient& d) const {
  assert(k < seq.size());
  const ITV& seq_k = seq[k];

  if (seq_k.upper_is_unbounded())
    return false;

  closed = !seq_k.upper_is_open();

  PPL_DIRTY_TEMP0(mpq_class, ur);
  assign_r(ur, seq_k.upper(), ROUND_NOT_NEEDED);
  n = ur.get_num();
  d = ur.get_den();

  return true;
}

template <typename ITV>
inline void
Box<ITV>::add_constraint(const Constraint& c) {
  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);

  add_constraint_no_check(c);
}

template <typename ITV>
inline void
Box<ITV>::add_constraints(const Constraint_System& cs) {
  // Dimension-compatibility check.
  if (cs.space_dimension() > space_dimension())
    throw_dimension_incompatible("add_constraints(cs)", cs);

  add_constraints_no_check(cs);
}

template <typename T>
inline void
Box<T>::add_recycled_constraints(Constraint_System& cs) {
  add_constraints(cs);
}

template <typename ITV>
inline void
Box<ITV>::add_congruence(const Congruence& cg) {
  const dimension_type cg_space_dim = cg.space_dimension();
  // Dimension-compatibility check.
  if (cg_space_dim > space_dimension())
    throw_dimension_incompatible("add_congruence(cg)", cg);

  add_congruence_no_check(cg);
}

template <typename ITV>
inline void
Box<ITV>::add_congruences(const Congruence_System& cgs) {
  if (cgs.space_dimension() > space_dimension())
    throw_dimension_incompatible("add_congruences(cgs)", cgs);
  add_congruences_no_check(cgs);
}

template <typename T>
inline void
Box<T>::add_recycled_congruences(Congruence_System& cgs) {
  add_congruences(cgs);
}

template <typename T>
inline bool
Box<T>::can_recycle_constraint_systems() {
  return false;
}

template <typename T>
inline bool
Box<T>::can_recycle_congruence_systems() {
  return false;
}

template <typename T>
inline void
Box<T>::widening_assign(const Box& y, unsigned* tp) {
  CC76_widening_assign(y, tp);
}

template <typename ITV>
inline Congruence_System
Box<ITV>::minimized_congruences() const {
  // Only equalities can be congruences and these are already minimized.
  return congruences();
}

template <typename ITV>
inline void
Box<ITV>
::add_interval_constraint_no_check(const dimension_type var_id,
                                   const Constraint::Type type,
                                   Coefficient_traits::const_reference num,
                                   Coefficient_traits::const_reference den) {
  assert(!marked_empty());
  assert(var_id < space_dimension());
  assert(den != 0);

  // The interval constraint is of the form
  // `Variable(var_id) + num / den rel 0', where
  // `rel' is either the relation `==', `>=', or `>'.
  // For the purpose of refining the interval, this is
  // (morally) turned into `Variable(var_id) rel -num/den'.
  PPL_DIRTY_TEMP0(mpq_class, q);
  assign_r(q.get_num(), num, ROUND_NOT_NEEDED);
  assign_r(q.get_den(), den, ROUND_NOT_NEEDED);
  q.canonicalize();
  // Turn `num/den' into `-num/den'.
  q = -q;

  ITV& seq_v = seq[var_id];
  switch (type) {
  case Constraint::EQUALITY:
    seq_v.refine_existential(EQUAL, q);
    break;
  case Constraint::NONSTRICT_INEQUALITY:
    seq_v.refine_existential((den > 0) ? GREATER_OR_EQUAL : LESS_OR_EQUAL, q);
    assert(seq_v.OK());
    break;
  case Constraint::STRICT_INEQUALITY:
    seq_v.refine_existential((den > 0) ? GREATER_THAN : LESS_THAN, q);
    break;
  }
  // FIXME: do check the value returned by `refine_existential' and
  // set `empty' and `empty_up_to_date' as appropriate.
  // This has to be done after reimplementation of intervals.
  reset_empty_up_to_date();
  assert(OK());
}

template <typename ITV>
inline void
Box<ITV>::refine_with_constraint(const Constraint& c) {
  const dimension_type c_space_dim = c.space_dimension();
  // Dimension-compatibility check.
  if (c_space_dim > space_dimension())
    throw_dimension_incompatible("refine_with_constraint(c)", c);

  // If the box is already empty, there is nothing left to do.
  if (marked_empty())
    return;

  refine_no_check(c);
}

template <typename ITV>
inline void
Box<ITV>::refine_with_constraints(const Constraint_System& cs) {
  // Dimension-compatibility check.
  if (cs.space_dimension() > space_dimension())
    throw_dimension_incompatible("refine_with_constraints(cs)", cs);

  // If the box is already empty, there is nothing left to do.
  if (marked_empty())
    return;

  refine_no_check(cs);
}

template <typename ITV>
inline void
Box<ITV>::refine_with_congruence(const Congruence& cg) {
  const dimension_type cg_space_dim = cg.space_dimension();
  // Dimension-compatibility check.
  if (cg_space_dim > space_dimension())
    throw_dimension_incompatible("refine_with_congruence(cg)", cg);

  // If the box is already empty, there is nothing left to do.
  if (marked_empty())
    return;

  refine_no_check(cg);
}

template <typename ITV>
inline void
Box<ITV>::refine_with_congruences(const Congruence_System& cgs) {
  // Dimension-compatibility check.
  if (cgs.space_dimension() > space_dimension())
    throw_dimension_incompatible("refine_with_congruences(cgs)", cgs);

  // If the box is already empty, there is nothing left to do.
  if (marked_empty())
    return;

  refine_no_check(cgs);
}

template <typename ITV>
inline void
Box<ITV>::propagate_constraint(const Constraint& c) {
  const dimension_type c_space_dim = c.space_dimension();
  // Dimension-compatibility check.
  if (c_space_dim > space_dimension())
    throw_dimension_incompatible("propagate_constraint(c)", c);

  // If the box is already empty, there is nothing left to do.
  if (marked_empty())
    return;

  propagate_constraint_no_check(c);
}

template <typename ITV>
inline void
Box<ITV>::propagate_constraints(const Constraint_System& cs) {
  // Dimension-compatibility check.
  if (cs.space_dimension() > space_dimension())
    throw_dimension_incompatible("propagate_constraints(cs)", cs);

  // If the box is already empty, there is nothing left to do.
  if (marked_empty())
    return;

  propagate_constraints_no_check(cs);
}

template <typename ITV>
inline void
Box<ITV>::unconstrain(const Variable var) {
  const dimension_type dim = var.id();
  // Dimension-compatibility check.
  if (dim > space_dimension())
    throw_dimension_incompatible("unconstrain(var)", dim);

  // If the box is already empty, there is nothing left to do.
  if (marked_empty())
    return;
  // Here the box might still be empty (but we haven't detected it yet):
  // check emptiness of the interval for `var' before cylindrification.
  ITV& seq_var = seq[dim];
  if (seq_var.is_empty())
    set_empty();
  else
    seq_var.assign(UNIVERSE);
  assert(OK());
}

/*! \relates Box */
template <typename Temp, typename To, typename ITV>
inline bool
rectilinear_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			    const Box<ITV>& x,
			    const Box<ITV>& 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);
}

/*! \relates Box */
template <typename Temp, typename To, typename ITV>
inline bool
rectilinear_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			    const Box<ITV>& x,
			    const Box<ITV>& y,
			    const Rounding_Dir dir) {
  typedef Checked_Number<Temp, Extended_Number_Policy> Checked_Temp;
  PPL_DIRTY_TEMP(Checked_Temp, tmp0);
  PPL_DIRTY_TEMP(Checked_Temp, tmp1);
  PPL_DIRTY_TEMP(Checked_Temp, tmp2);
  return rectilinear_distance_assign(r, x, y, dir, tmp0, tmp1, tmp2);
}

/*! \relates Box */
template <typename To, typename ITV>
inline bool
rectilinear_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			    const Box<ITV>& x,
			    const Box<ITV>& y,
			    const Rounding_Dir dir) {
  // FIXME: the following qualification is only to work around a bug
  // in the Intel C/C++ compiler version 10.1.x.
  return Parma_Polyhedra_Library
    ::rectilinear_distance_assign<To, To, ITV>(r, x, y, dir);
}

/*! \relates Box */
template <typename Temp, typename To, typename ITV>
inline bool
euclidean_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			  const Box<ITV>& x,
			  const Box<ITV>& 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);
}

/*! \relates Box */
template <typename Temp, typename To, typename ITV>
inline bool
euclidean_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			  const Box<ITV>& x,
			  const Box<ITV>& y,
			  const Rounding_Dir dir) {
  typedef Checked_Number<Temp, Extended_Number_Policy> Checked_Temp;
  PPL_DIRTY_TEMP(Checked_Temp, tmp0);
  PPL_DIRTY_TEMP(Checked_Temp, tmp1);
  PPL_DIRTY_TEMP(Checked_Temp, tmp2);
  return euclidean_distance_assign(r, x, y, dir, tmp0, tmp1, tmp2);
}

/*! \relates Box */
template <typename To, typename ITV>
inline bool
euclidean_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			  const Box<ITV>& x,
			  const Box<ITV>& y,
			  const Rounding_Dir dir) {
  // FIXME: the following qualification is only to work around a bug
  // in the Intel C/C++ compiler version 10.1.x.
  return Parma_Polyhedra_Library
    ::euclidean_distance_assign<To, To, ITV>(r, x, y, dir);
}

/*! \relates Box */
template <typename Temp, typename To, typename ITV>
inline bool
l_infinity_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			   const Box<ITV>& x,
			   const Box<ITV>& 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);
}

/*! \relates Box */
template <typename Temp, typename To, typename ITV>
inline bool
l_infinity_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			   const Box<ITV>& x,
			   const Box<ITV>& y,
			   const Rounding_Dir dir) {
  typedef Checked_Number<Temp, Extended_Number_Policy> Checked_Temp;
  PPL_DIRTY_TEMP(Checked_Temp, tmp0);
  PPL_DIRTY_TEMP(Checked_Temp, tmp1);
  PPL_DIRTY_TEMP(Checked_Temp, tmp2);
  return l_infinity_distance_assign(r, x, y, dir, tmp0, tmp1, tmp2);
}

/*! \relates Box */
template <typename To, typename ITV>
inline bool
l_infinity_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			   const Box<ITV>& x,
			   const Box<ITV>& y,
			   const Rounding_Dir dir) {
  // FIXME: the following qualification is only to work around a bug
  // in the Intel C/C++ compiler version 10.1.x.
  return Parma_Polyhedra_Library
    ::l_infinity_distance_assign<To, To, ITV>(r, x, y, dir);
}

} // namespace Parma_Polyhedra_Library

/* Automatically generated from PPL source file ../src/Box.templates.hh line 1. */
/* Box class implementation: non-inline template functions.
*/


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


/* 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.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/DB_Row.defs.hh line 1. */
/* DB_Row class declaration.
*/


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


namespace Parma_Polyhedra_Library {

template <typename T>
class DB_Row_Impl_Handler;

template <typename T>
class DB_Row;

} // namespace Parma_Polyhedra_Library

/* 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.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/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 // defined(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 29. */
#include <cstddef>
#include <vector>

#ifndef PPL_DB_ROW_EXTRA_DEBUG
#ifdef PPL_ABI_BREAKING_EXTRA_DEBUG
#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \brief
  When PPL_DB_ROW_EXTRA_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 // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
#define PPL_DB_ROW_EXTRA_DEBUG 1
#else // !defined(PPL_ABI_BREAKING_EXTRA_DEBUG)
#define PPL_DB_ROW_EXTRA_DEBUG 0
#endif // !defined(PPL_ABI_BREAKING_EXTRA_DEBUG)
#endif // !defined(PPL_DB_ROW_EXTRA_DEBUG)


#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 // defined(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 PPL_DB_ROW_EXTRA_DEBUG
  //! The capacity of \p impl (only available during debugging).
  dimension_type capacity_;
#endif // PPL_DB_ROW_EXTRA_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 // defined(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;

  /*! \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:
  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 PPL_DB_ROW_EXTRA_DEBUG
  //! Returns the capacity of the row (only available during debugging).
  dimension_type capacity() const;
#endif // PPL_DB_ROW_EXTRA_DEBUG
};

namespace Parma_Polyhedra_Library {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! \name Classical comparison operators.
//@{
#endif // defined(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 // defined(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 // defined(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;
  //@}

  /*! \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:
  friend class DB_Row<T>;

  //! The number of coefficients in the row.
  dimension_type size_;

  //! The vector of coefficients.
  T vec_[
#if !PPL_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 // defined(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 // defined(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.
*/


/* Automatically generated from PPL source file ../src/DB_Row.inlines.hh line 27. */
#include <cassert>
#include <cstddef>
#include <limits>
#include <algorithm>
#include <iostream>

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 PPL_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 memory_size_type
DB_Row_Impl_Handler<T>::Impl
::total_memory_in_bytes(dimension_type capacity) const {
  return
    sizeof(*this)
    + capacity*sizeof(T)
#if !PPL_CXX_SUPPORTS_FLEXIBLE_ARRAYS
    - 1*sizeof(T)
#endif
    + external_memory_in_bytes();
}

template <typename T>
inline memory_size_type
DB_Row_Impl_Handler<T>::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_);
}

template <typename T>
inline dimension_type
DB_Row_Impl_Handler<T>::Impl::max_size() {
  return std::numeric_limits<size_t>::max() / 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 PPL_DB_ROW_EXTRA_DEBUG
  capacity_ = 0;
#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 PPL_DB_ROW_EXTRA_DEBUG
template <typename T>
inline dimension_type
DB_Row<T>::capacity() const {
  return this->capacity_;
}
#endif // PPL_DB_ROW_EXTRA_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 PPL_CXX_SUPPORTS_FLEXIBLE_ARRAYS
	       const
#endif
	       dimension_type capacity) {
  DB_Row<T>& x = *this;
  assert(capacity <= max_size());
#if !PPL_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 PPL_DB_ROW_EXTRA_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 PPL_DB_ROW_EXTRA_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 PPL_DB_ROW_EXTRA_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 PPL_DB_ROW_EXTRA_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 PPL_DB_ROW_EXTRA_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 typename DB_Row<T>::iterator
DB_Row<T>::begin() {
  DB_Row<T>& x = *this;
  return iterator(x.impl->vec_);
}

template <typename T>
inline 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>
inline 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>
inline 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 memory_size_type
DB_Row<T>::external_memory_in_bytes(dimension_type capacity) const {
  const DB_Row<T>& x = *this;
  return x.impl->total_memory_in_bytes(capacity);
}

template <typename T>
inline memory_size_type
DB_Row<T>::total_memory_in_bytes(dimension_type capacity) const {
  return sizeof(*this) + external_memory_in_bytes(capacity);
}

template <typename T>
inline memory_size_type
DB_Row<T>::external_memory_in_bytes() const {
  const DB_Row<T>& x = *this;
#if PPL_DB_ROW_EXTRA_DEBUG
  return x.impl->total_memory_in_bytes(x.capacity_);
#else
  return x.impl->total_memory_in_bytes();
#endif
}

template <typename T>
inline memory_size_type
DB_Row<T>::total_memory_in_bytes() const {
  return sizeof(*this) + external_memory_in_bytes();
}

/*! \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.templates.hh line 1. */
/* DB_Row class implementation: non-inline template functions.
*/


/* Automatically generated from PPL source file ../src/DB_Row.templates.hh line 27. */

namespace Parma_Polyhedra_Library {

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 PPL_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 // PPL_CXX_SUPPORTS_FLEXIBLE_ARRAYS
  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 // PPL_CXX_SUPPORTS_FLEXIBLE_ARRAYS
}

template <typename T>
void
DB_Row_Impl_Handler<T>::
Impl::expand_within_capacity(const dimension_type new_size) {
  assert(size() <= new_size && new_size <= max_size());
#if !PPL_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, ROUND_NOT_NEEDED);
    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 !PPL_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 PPL_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 // PPL_CXX_SUPPORTS_FLEXIBLE_ARRAYS
  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 // PPL_CXX_SUPPORTS_FLEXIBLE_ARRAYS
}

template <typename T>
memory_size_type
DB_Row_Impl_Handler<T>::Impl::external_memory_in_bytes() const {
  memory_size_type n = 0;
  for (dimension_type i = size(); i-- > 0; )
    n += Parma_Polyhedra_Library::external_memory_in_bytes(vec_[i]);
  return n;
}

template <typename T>
bool
DB_Row<T>::OK(const dimension_type row_size,
	      const dimension_type
#if PPL_DB_ROW_EXTRA_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 PPL_DB_ROW_EXTRA_DEBUG
# if !PPL_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 // !PPL_CXX_SUPPORTS_FLEXIBLE_ARRAYS
  if (x.capacity_ != row_capacity) {
    cerr << "DB_Row capacity mismatch: is " << x.capacity_
	 << ", should be " << row_capacity << "."
	 << endl;
    is_broken = true;
  }
#endif // PPL_DB_ROW_EXTRA_DEBUG

  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 PPL_DB_ROW_EXTRA_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 // PPL_DB_ROW_EXTRA_DEBUG

  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>
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;
}

} // namespace Parma_Polyhedra_Library

/* Automatically generated from PPL source file ../src/DB_Row.defs.hh line 473. */

/* 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 // defined(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 template 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 // defined(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 // defined(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
    ascii_dump(std::ostream&) const) 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;

  //! 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 // defined(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 // defined(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 // defined(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 // defined(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,
				 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 // defined(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,
			       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 // defined(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,
				 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 29. */
#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 memory_size_type
DB_Matrix<T>::total_memory_in_bytes() const {
  return sizeof(*this) + external_memory_in_bytes();
}

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 // defined(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 DB_Matrix& y)
  : rows(y.rows),
    row_size(y.row_size),
    row_capacity(compute_capacity(y.row_size, max_num_columns())) {
}

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;
}

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \relates DB_Matrix */
#endif // defined(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:
	  assign_r(r, PLUS_INFINITY, ROUND_NOT_NEEDED);
	  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(sgn(tmp1) >= 0);
      Specialization::combine(tmp0, tmp1, dir);
    }
  }
  Specialization::finalize(tmp0, dir);
  assign_r(r, tmp0, dir);
  return true;
}

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \relates DB_Matrix */
#endif // defined(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);
}


#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \relates DB_Matrix */
#endif // defined(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);
}

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \relates DB_Matrix */
#endif // defined(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);
}

} // namespace Parma_Polyhedra_Library

namespace std {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \relates Parma_Polyhedra_Library::DB_Matrix */
#endif // defined(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.templates.hh line 1. */
/* DB_Matrix class implementation: non-inline template functions.
*/


namespace Parma_Polyhedra_Library {

template <typename T>
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>
template <typename U>
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>
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) {
	// FIXME: copying may be unnecessarily costly.
	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; ) {
	// FIXME: copying may be unnecessarily costly.
	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_CHECK);
      if (r != V_EQ || is_minus_infinity(x[i][j]))
	return false;
    }

  // Check invariants.
  assert(OK());
  return true;
}

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \relates DB_Matrix */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename T>
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 T>
memory_size_type
DB_Matrix<T>::external_memory_in_bytes() const {
  memory_size_type n = rows.capacity() * sizeof(DB_Row<T>);
  for (dimension_type i = num_rows(); i-- > 0; )
    n += rows[i].external_memory_in_bytes(row_capacity);
  return n;
}

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 */
#endif // defined(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

/* Automatically generated from PPL source file ../src/DB_Matrix.defs.hh line 330. */

/* Automatically generated from PPL source file ../src/BD_Shape.defs.hh line 47. */
#include <cstddef>
#include <iosfwd>
#include <vector>

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,
                                 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,
                                 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,
                                 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,
                               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,
                               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,
                               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,
                                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,
                                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,
                                Rounding_Dir dir,
                                Temp& tmp0,
                                Temp& tmp1,
                                Temp& tmp2);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Decodes the constraint \p c as a bounded difference.
/*! \relates BD_Shape
  \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 // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
bool extract_bounded_difference(const Constraint& c,
                                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.
/*! \relates BD_Shape */
#endif // defined(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.

  The domain of BD shapes <EM>optimally supports</EM>:
    - tautological and inconsistent constraints and congruences;
    - bounded difference constraints;
    - non-proper congruences (i.e., equalities) that are expressible
      as bounded-difference constraints.

  Depending on the method, using a constraint or congruence that is not
  optimally supported by the domain will either raise an exception or
  result in a (possibly non-optimal) upward approximation.

  A constraint is a bounded difference if it has 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 bounded difference Constraint object
  will be mapped into a \e correct and \e optimal approximation that,
  depending on the expressive power of the chosen template argument \p T,
  may loose some precision. Also note that strict constraints are not
  bounded differences.

  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, depending from the context, a Constraint object
  encoding \f$3x - y \leq 1\f$ will be either upward approximated
  (e.g., by safely ignoring it) or it will cause an exception.

  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 optimally supported, the following code
  will throw an exception (caused by constraints 7, 8 and 9):
  \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 coefficient_type_base;

  /*! \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();

  /*! \brief
    Returns \c false indicating that this domain cannot recycle constraints.
  */
  static bool can_recycle_constraint_systems();

  /*! \brief
    Returns \c false indicating that this domain cannot recycle congruences.
  */
  static bool can_recycle_congruence_systems();

  //! \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.
  /*!
    The complexity argument is ignored.
  */
  BD_Shape(const BD_Shape& y,
           Complexity_Class complexity = ANY_COMPLEXITY);

  //! Builds a conservative, upward approximation of \p y.
  /*!
    The complexity argument is ignored.
  */
  template <typename U>
  explicit BD_Shape(const BD_Shape<U>& y,
                    Complexity_Class complexity = ANY_COMPLEXITY);

  //! 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 \p cs contains a constraint which is not optimally supported
    by the BD shape domain.
  */
  explicit BD_Shape(const Constraint_System& cs);

  //! Builds a BDS from a system of congruences.
  /*!
    The BDS inherits the space dimension of \p cgs

    \param cgs
    A system of congruences: some elements may be safely ignored.
  */
  explicit BD_Shape(const Congruence_System& cgs);

  //! 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.
  */
  explicit 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.
  */
  explicit BD_Shape(const Polyhedron& ph,
                    Complexity_Class complexity = ANY_COMPLEXITY);

  //! Builds a BDS out of a box.
  /*!
    The BDS inherits the space dimension of the box.
    The built BDS is the most precise BDS that includes the box.

    \param box
    The box representing the BDS to be built.

    \param complexity
    This argument is ignored as the algorithm used has
    polynomial complexity.

    \exception std::length_error
    Thrown if the space dimension of \p box exceeds the maximum
    allowed space dimension.
  */
  template <typename Interval>
  explicit BD_Shape(const Box<Interval>& box,
                    Complexity_Class complexity = ANY_COMPLEXITY);

  //! Builds a BDS out of a grid.
  /*!
    The BDS inherits the space dimension of the grid.
    The built BDS is the most precise BDS that includes the grid.

    \param grid
    The grid used to build the BDS.

    \param complexity
    This argument is ignored as the algorithm used has
    polynomial complexity.

    \exception std::length_error
    Thrown if the space dimension of \p grid exceeds the maximum
    allowed space dimension.
  */
  explicit BD_Shape(const Grid& grid,
                    Complexity_Class complexity = ANY_COMPLEXITY);

  //! Builds a BDS from an octagonal shape.
  /*!
    The BDS inherits the space dimension of the octagonal shape.
    The built BDS is the most precise BDS that includes the octagonal shape.

    \param os
    The octagonal shape used to build the BDS.

    \param complexity
    This argument is ignored as the algorithm used has
    polynomial complexity.

    \exception std::length_error
    Thrown if the space dimension of \p os exceeds the maximum
    allowed space dimension.
  */
  template <typename U>
  explicit BD_Shape(const Octagonal_Shape<U>& os,
                    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 a system of (equality) congruences satisfied by \p *this.
  Congruence_System congruences() const;

  /*! \brief
    Returns a minimal system of (equality) congruences
    satisfied by \p *this with the same affine dimension as \p *this.
  */
  Congruence_System minimized_congruences() 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 g
    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 g are left untouched.
  */
  bool maximize(const Linear_Expression& expr,
                Coefficient& sup_n, Coefficient& sup_d, bool& maximum,
                Generator& g) 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 g
    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 g are left untouched.
  */
  bool minimize(const Linear_Expression& expr,
                Coefficient& inf_n, Coefficient& inf_d, bool& minimum,
                Generator& g) 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 <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 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.
  */
  Poly_Con_Relation relation_with(const Constraint& c) const;

  //! Returns the relations holding between \p *this and the congruence \p cg.
  /*!
    \exception std::invalid_argument
    Thrown if \p *this and congruence \p cg are dimension-incompatible.
  */
  Poly_Con_Relation relation_with(const Congruence& cg) 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;

  //! Returns <CODE>true</CODE> if and only if \p *this is discrete.
  bool is_discrete() 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 is a bounded BDS.
  bool is_bounded() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this
    contains at least one integer point.
  */
  bool contains_integer_point() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p var is constrained in
    \p *this.

    \exception std::invalid_argument
    Thrown if \p var is not a space dimension of \p *this.
  */
  bool constrains(Variable var) 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 \p c is not optimally supported by the BD shape domain.
  */
  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 \p c is not optimally supported by the BD shape domain.

    \deprecated
    See \ref A_Note_on_the_Implementation_of_the_Operators.
  */
  bool add_constraint_and_minimize(const Constraint& c);

  /*! \brief
    Adds a copy of congruence \p cg to the system of congruences of \p *this.

    \param cg
    The congruence to be added.

    \exception std::invalid_argument
    Thrown if \p *this and congruence \p cg are dimension-incompatible,
    or \p cg is not optimally supported by the BD shape domain.
  */
  void add_congruence(const Congruence& cg);

  /*! \brief
    Adds a copy of congruence \p cg to the system of congruences
    of \p *this, minimizing the result

    \param cg
    The congruence to be added.

    \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,
    or \p cg is not optimally supported by the BD shape domain.

    \deprecated
    See \ref A_Note_on_the_Implementation_of_the_Operators.
  */
  bool add_congruence_and_minimize(const Congruence& cg);

  /*! \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 \p cs contains a constraint which is not optimally supported
    by the BD shape domain.
  */
  void add_constraints(const Constraint_System& cs);

  /*! \brief
    Adds the constraints in \p cs to the system of constraints
    of \p *this.

    \param cs
    The constraint system to be added to \p *this.  The constraints in
    \p cs may be recycled.

    \exception std::invalid_argument
    Thrown if \p *this and \p cs are dimension-incompatible,
    or \p cs contains a constraint which is not optimally supported
    by the BD shape domain.

    \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 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.

    \exception std::invalid_argument
    Thrown if \p *this and \p cs are dimension-incompatible,
    or \p cs contains a constraint which is not optimally supported
    by the BD shape domain.

    \deprecated
    See \ref A_Note_on_the_Implementation_of_the_Operators.
  */
  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 to be added to \p *this.  The constraints in
    \p cs may be recycled.

    \exception std::invalid_argument
    Thrown if \p *this and \p cs are dimension-incompatible,
    or \p cs contains a constraint which is not optimally supported
    by the BD shape domain.

    \warning
    The only assumption that can be made on \p cs upon successful or
    exceptional return is that it can be safely destroyed.

    \deprecated
    See \ref A_Note_on_the_Implementation_of_the_Operators.
  */
  bool add_recycled_constraints_and_minimize(Constraint_System& cs);

  /*! \brief
    Adds to \p *this constraints equivalent to the congruences in \p cgs.

    \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 dimension-incompatible,
    or \p cgs contains a congruence which is not optimally supported
    by the BD shape domain.
  */
  void add_congruences(const Congruence_System& cgs);

  /*! \brief
    Behaves as add_congruences(const Congruence_System&),
    but minimizes the resulting BD shape, returning \c false
    if and only if the result is empty.

    \deprecated
    See \ref A_Note_on_the_Implementation_of_the_Operators.
  */
  bool add_congruences_and_minimize(const Congruence_System& cgs);

  /*! \brief
    Adds to \p *this constraints equivalent to the congruences in \p cgs.

    \param cgs
    Contains the congruences that will be added to the system of
    constraints of \p *this. Its elements may be recycled.

    \exception std::invalid_argument
    Thrown if \p *this and \p cgs are dimension-incompatible,
    or \p cgs contains a congruence which is not optimally supported
    by the BD shape domain.

    \warning
    The only assumption that can be made on \p cgs upon successful or
    exceptional return is that it can be safely destroyed.
  */
  void add_recycled_congruences(Congruence_System& cgs);

  /*! \brief
    Behaves as \c add_recycled_congruences, but minimizes the
    resulting BD shape, returning \c false if and only if
    the result is empty.

    \deprecated
    See \ref A_Note_on_the_Implementation_of_the_Operators.
  */
  bool add_recycled_congruences_and_minimize(Congruence_System& cgs);

  /*! \brief
    Uses a copy of constraint \p c to refine the system of bounded differences
    defining \p *this.

    \param c
    The constraint. If it is not a bounded difference, it will be ignored.

    \exception std::invalid_argument
    Thrown if \p *this and constraint \p c are dimension-incompatible.
  */
  void refine_with_constraint(const Constraint& c);

  /*! \brief
    Uses a copy of congruence \p cg to refine the system of
    bounded differences  of \p *this.

    \param cg
    The congruence. If it is not a bounded difference equality, it
    will be ignored.

    \exception std::invalid_argument
    Thrown if \p *this and congruence \p cg are dimension-incompatible.
  */
  void refine_with_congruence(const Congruence& cg);

  /*! \brief
    Uses a copy of the constraints in \p cs to refine the system of
    bounded differences defining \p *this.

    \param  cs
    The constraint system to be used. Constraints that are not bounded
    differences are ignored.

    \exception std::invalid_argument
    Thrown if \p *this and \p cs are dimension-incompatible.
  */
  void refine_with_constraints(const Constraint_System& cs);

  /*! \brief
    Uses a copy of the congruences in \p cgs to refine the system of
    bounded differences defining \p *this.

    \param  cgs
    The congruence system to be used. Congruences that are not bounded
    difference equalities are ignored.

    \exception std::invalid_argument
    Thrown if \p *this and \p cgs are dimension-incompatible.
  */
  void refine_with_congruences(const Congruence_System& cgs);

  /*! \brief
    Computes the \ref Cylindrification "cylindrification" of \p *this with
    respect to space dimension \p var, assigning the result to \p *this.

    \param var
    The space dimension that will be unconstrained.

    \exception std::invalid_argument
    Thrown if \p var is not a space dimension of \p *this.
  */
  void unconstrain(Variable var);

  /*! \brief
    Computes the \ref Cylindrification "cylindrification" of \p *this with
    respect to the set of space dimensions \p to_be_unconstrained,
    assigning the result to \p *this.

    \param to_be_unconstrained
    The set of space dimension that will be unconstrained.

    \exception std::invalid_argument
    Thrown if \p *this is dimension-incompatible with one of the
    Variable objects contained in \p to_be_removed.
  */
  void unconstrain(const Variables_Set& to_be_unconstrained);

  //! 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.

    \deprecated
    See \ref A_Note_on_the_Implementation_of_the_Operators.
  */
  bool intersection_assign_and_minimize(const BD_Shape& y);

  /*! \brief
    Assigns to \p *this the smallest BDS containing the union
    of \p *this and \p y.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are dimension-incompatible.
  */
  void upper_bound_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.

    \deprecated
    See \ref A_Note_on_the_Implementation_of_the_Operators.
  */
  bool upper_bound_assign_and_minimize(const BD_Shape& y);

  /*! \brief
    If the upper bound 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 upper_bound_assign_if_exact(const BD_Shape& y);

  /*! \brief
    Assigns to \p *this the smallest BD shape containing
    the set difference of \p *this and \p y.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are dimension-incompatible.
  */
  void difference_assign(const BD_Shape& y);

  /*! \brief
    Assigns to \p *this a \ref Meet_Preserving_Simplification
    "meet-preserving simplification" of \p *this with respect to \p y.
    If \c false is returned, then the intersection is empty.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are topology-incompatible or
    dimension-incompatible.
  */
  bool simplify_using_context_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 preimage 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_preimage(const Linear_Expression& lhs,
                                   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 dimension-incompatible.
  */
  void time_elapse_assign(const BD_Shape& y);

  //! Assigns to \p *this its topological closure.
  void topological_closure_assign();

  /*! \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>decreasing</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);

  //! Same as H79_widening_assign(y, tp).
  void 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
    Assigns to \p *this the \ref Concatenating_Polyhedra "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 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 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 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 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

  PPL_OUTPUT_DECLARATIONS

  /*! \brief
    Loads from \p s an ASCII representation (as produced by
    ascii_dump(std::ostream&) const) 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
    Returns a 32-bit hash code for \p *this.

    If \p x and \p y are such that <CODE>x == y</CODE>,
    then <CODE>x.hash_code() == y.hash_code()</CODE>.
  */
  int32_t hash_code() const;

  friend bool 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;
  template <typename Interval> friend class Parma_Polyhedra_Library::Box;

  //! 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-dimensional
    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
    ascii_dump(std::ostream&) const) 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 1800. */
#undef PPL_IN_BD_Shape_CLASS

  //! The status flags to keep track of the internal state.
  Status status;

  //! A matrix indicating which constraints are redundant.
  Bit_Matrix redundancy_dbm;

  //! Returns <CODE>true</CODE> if the BDS is the zero-dimensional universe.
  bool marked_zero_dim_univ() const;

  /*! \brief
    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();

  //! Marks \p *this as shortest-path closed.
  void set_shortest_path_closed();

  //! Marks \p *this as shortest-path closed.
  void set_shortest_path_reduced();

  //! Marks \p *this as possibly not shortest-path closed.
  void reset_shortest_path_closed();

  //! Marks \p *this as possibly not shortest-path reduced.
  void reset_shortest_path_reduced();

  //! 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;

  /*! \brief
    Incrementally computes shortest-path closure, assuming that only
    constraints affecting variable \p var need to be considered.

    \note
    It is assumed that \c *this, which was shortest-path closed,
    has only been modified by adding constraints affecting variable
    \p var. If this assumption is not satisfied, i.e., if a non-redundant
    constraint not affecting variable \p var has been added, the behavior
    is undefined.
  */
  void incremental_shortest_path_closure_assign(Variable var) 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 g
    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 g are left untouched.
  */
  bool max_min(const Linear_Expression& expr,
               bool maximize,
               Coefficient& ext_n, Coefficient& ext_d, bool& included,
               Generator& g) 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;

    \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,
               bool maximize,
               Coefficient& ext_n, Coefficient& ext_d, bool& included) const;

  /*! \brief
    If the upper bound of \p *this and \p y is exact it is assigned
    to \p *this and \c true is returned, otherwise \c false is returned.

    Current implementation is based on a variant of Algorithm 4.1 in
      A. Bemporad, K. Fukuda, and F. D. Torrisi
      <em>Convexity Recognition of the Union of Polyhedra</em>
      Technical Report AUT00-13, ETH Zurich, 2000
    tailored to the special case of BD shapes.

    \note
    It is assumed that \p *this and \p y are dimension-compatible;
    if the assumption does not hold, the behavior is undefined.
  */
  bool BFT00_upper_bound_assign_if_exact(const BD_Shape& y);

  bool BHZ09_upper_bound_assign_if_exact(const BD_Shape& y);

  /*! \brief
    Uses the constraint \p c to refine \p *this.

    \param c
    The constraint to be added. Non BD constraints are ignored.

    \warning
    If \p c and \p *this are dimension-incompatible,
    the behavior is undefined.
  */
  void refine_no_check(const Constraint& c);

  /*! \brief
    Uses the congruence \p cg to refine \p *this.

    \param cg
    The congruence to be added.
    Nontrivial proper congruences are ignored.
    Non BD equalities are ignored.

    \warning
    If \p cg and \p *this are dimension-incompatible,
    the behavior is undefined.
  */
  void refine_no_check(const Congruence& cg);

  //! Adds the constraint <CODE>dbm[i][j] \<= k</CODE>.
  void add_dbm_constraint(dimension_type i, dimension_type j, const 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);

  /*! \brief
    Adds to the BDS the constraint
    \f$\mathrm{var} \relsym \frac{\mathrm{expr}}{\mathrm{denominator}}\f$.

    Note that the coefficient of \p var in \p expr is null.
  */
  void refine(Variable var, Relation_Symbol relsym,
              const Linear_Expression& expr,
              Coefficient_traits::const_reference denominator
              = Coefficient_one());

  //! 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 ub_v 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& ub_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>u - v \<= c</CODE>,
    starting from \p minus_lb_v 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& minus_lb_v);

  /*! \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;

  friend std::ostream&
  Parma_Polyhedra_Library::IO_Operators
  ::operator<<<>(std::ostream& s, const BD_Shape<T>& c);

  //! \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 Congruence& cg) 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_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;
  PPL_UNINITIALIZED(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 invariants.
  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/Octagonal_Shape.defs.hh line 1. */
/* Octagonal_Shape class declaration.
*/


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


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


namespace Parma_Polyhedra_Library {

template <typename T>
class OR_Matrix;

}

/* Automatically generated from PPL source file ../src/OR_Matrix.defs.hh line 31. */
#include <cstddef>
#include <iosfwd>

#ifndef PPL_OR_MATRIX_EXTRA_DEBUG
#ifdef PPL_ABI_BREAKING_EXTRA_DEBUG
#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \brief
  When PPL_OR_MATRIX_EXTRA_DEBUG evaluates to <CODE>true</CODE>, each
  instance of the class OR_Matrix::Pseudo_Row carries its own size;
  this enables extra consistency checks to be performed.
  \ingroup PPL_CXX_interface
*/
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
#define PPL_OR_MATRIX_EXTRA_DEBUG 1
#else // !defined(PPL_ABI_BREAKING_EXTRA_DEBUG)
#define PPL_OR_MATRIX_EXTRA_DEBUG 0
#endif // !defined(PPL_ABI_BREAKING_EXTRA_DEBUG)
#endif // !defined(PPL_OR_MATRIX_EXTRA_DEBUG)

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 OR_Matrix */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename T>
bool operator==(const OR_Matrix<T>& x, const OR_Matrix<T>& y);

namespace IO_Operators {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Output operator.
/*! \relates Parma_Polyhedra_Library::OR_Matrix */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename T>
std::ostream&
operator<<(std::ostream& s, const OR_Matrix<T>& m);

} // namespace IO_Operators

} // namespace Parma_Polyhedra_Library


#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! A matrix representing octagonal constraints.
/*!
  An OR_Matrix object is a DB_Row object that allows
  the representation of a \em pseudo-triangular matrix,
  like the following:

<PRE>
         _ _
   0    |_|_|
   1    |_|_|_ _
   2    |_|_|_|_|
   3    |_|_|_|_|_ _
   4    |_|_|_|_|_|_|
   5    |_|_|_|_|_|_|
         . . .
         _ _ _ _ _ _       _
 2n-2   |_|_|_|_|_|_| ... |_|
 2n-1   |_|_|_|_|_|_| ... |_|
         0 1 2 3 4 5  ... 2n-1

</PRE>

  It is characterized by parameter n that defines the structure,
  and such that there are 2*n rows (and 2*n columns).
  It provides row_iterators for the access to the rows
  and element_iterators for the access to the elements.
*/
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)

template <typename T>
class Parma_Polyhedra_Library::OR_Matrix {
private:
  /*! \brief
    An object that behaves like a matrix's row with respect to
    the subscript operators.
  */
  template <typename U>
  class Pseudo_Row {
  public:
    /*! \brief
      Copy-constructor allowing the construction of a const pseudo-row
      from a non-const pseudo-row.
      Ordinary copy constructor.
    */
    template <typename V>
    Pseudo_Row(const Pseudo_Row<V>& y);

    //! Destructor.
    ~Pseudo_Row();

    //! Subscript operator.
    U& operator[](dimension_type k) const;

    //! Default constructor: creates an invalid object that has to be assigned.
    Pseudo_Row();

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

#if !defined(__GNUC__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 0)
  private:
#else
  // Work around a bug of GCC 4.0.x (and, likely, previous versions).
  public:
#endif

#if PPL_OR_MATRIX_EXTRA_DEBUG

    //! Private constructor for a Pseudo_Row with size \p s beginning at \p y.
    Pseudo_Row(U& y, dimension_type s);

#else // !PPL_OR_MATRIX_EXTRA_DEBUG

    //! Private constructor for a Pseudo_Row beginning at \p y.
    explicit Pseudo_Row(U& y);

#endif // !PPL_OR_MATRIX_EXTRA_DEBUG

    //! Holds a reference to the beginning of this row.
    U* first;

#if !defined(__GNUC__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 0)
#else
  // Work around a bug of GCC 4.0.x (and, likely, previous versions).
  private:
#endif

#if PPL_OR_MATRIX_EXTRA_DEBUG

    //! The size of the row.
    dimension_type size_;

    //! Returns the size of the row.
    dimension_type size() const;

#endif // PPL_OR_MATRIX_EXTRA_DEBUG

    // FIXME: the EDG-based compilers (such as Comeau and Intel)
    // are here in wild disagreement with GCC: what is a legal friend
    // declaration for one, is illegal for the others.
#ifdef __EDG__
    template <typename V> template<typename W>
    friend class OR_Matrix<V>::Pseudo_Row;
    template <typename V> template<typename W>
    friend class OR_Matrix<V>::any_row_iterator;
#else
    template <typename V> friend class Pseudo_Row;
    template <typename V> friend class any_row_iterator;
#endif

    friend class OR_Matrix;
  }; // class Pseudo_Row

public:
  //! A (non const) reference to a matrix's row.
  typedef Pseudo_Row<T> row_reference_type;

  //! A const reference to a matrix's row.
  typedef Pseudo_Row<const T> const_row_reference_type;

private:
  /*! \brief
    A template class to derive both OR_Matrix::iterator
    and OR_Matrix::const_iterator.
  */
  template <typename U>
  class any_row_iterator {
  public:
    typedef std::random_access_iterator_tag iterator_category;
    typedef Pseudo_Row<U> value_type;
    typedef long difference_type;
    typedef const Pseudo_Row<U>* pointer;
    typedef const Pseudo_Row<U>& reference;

    //! Constructor to build past-the-end objects.
    any_row_iterator(dimension_type n_rows);

    /*! \brief
      Builds an iterator pointing at the beginning of an OR_Matrix whose
      first element is \p base;
    */
    explicit any_row_iterator(U& base);

    /*! \brief
      Copy-constructor allowing the construction of a const_iterator
      from a non-const iterator.
    */
    template <typename V>
    any_row_iterator(const any_row_iterator<V>& y);

    /*! \brief
      Assignment operator allowing the assignment of a non-const iterator
      to a const_iterator.
    */
    template <typename V>
    any_row_iterator& operator=(const any_row_iterator<V>& y);

    //! Dereference operator.
    reference operator*() const;

    //! Indirect member selector.
    pointer operator->() const;

    //! Prefix increment operator.
    any_row_iterator& operator++();

    //! Postfix increment operator.
    any_row_iterator operator++(int);

    //! Prefix decrement operator.
    any_row_iterator& operator--();

    //! Postfix decrement operator.
    any_row_iterator operator--(int);

    //! Subscript operator.
    reference operator[](difference_type m) const;

    //! Assignment-increment operator.
    any_row_iterator& operator+=(difference_type m);

    //! Assignment-decrement operator.
    any_row_iterator& operator-=(difference_type m);

    //! Returns the difference between \p *this and \p y.
    difference_type operator-(const any_row_iterator& y) const;

    //! Returns the sum of \p *this and \p m.
    any_row_iterator operator+(difference_type m) const;

    //! Returns the difference of \p *this and \p m.
    any_row_iterator operator-(difference_type m) const;

    //! Returns <CODE>true</CODE> if and only if \p *this is equal to \p y.
    bool operator==(const any_row_iterator& y) const;

    /*! \brief
      Returns <CODE>true</CODE> if and only if \p *this
      is different from \p y.
    */
    bool operator!=(const any_row_iterator& y) const;

    //! Returns <CODE>true</CODE> if and only if \p *this is less than \p y.
    bool operator<(const any_row_iterator& y) const;

    /*! \brief
      Returns <CODE>true</CODE> if and only if \p *this is less than
      or equal to \p y.
    */
    bool operator<=(const any_row_iterator& y) const;

    //! Returns <CODE>true</CODE> if and only if \p *this is greater than \p y.
    bool operator>(const any_row_iterator& y) const;

    /*! \brief
      Returns <CODE>true</CODE> if and only if \p *this is greater than
      or equal to \p y.
    */
    bool operator>=(const any_row_iterator& y) const;

    dimension_type row_size() const;

    dimension_type index() const;

  private:
    //! Represents the beginning of a row.
    Pseudo_Row<U> value;

    //! External index.
    dimension_type e;

    //! Internal index: <CODE>i = (e+1)*(e+1)/2</CODE>.
    dimension_type i;

    // FIXME: the EDG-based compilers (such as Comeau and Intel)
    // are here in wild disagreement with GCC: what is a legal friend
    // declaration for one, is illegal for the others.
#ifdef __EDG__
    template <typename V> template<typename W>
    friend class OR_Matrix<V>::any_row_iterator;
#else
    template <typename V> friend class any_row_iterator;
#endif
  }; // class any_row_iterator

public:
  //! A (non const) row iterator.
  typedef any_row_iterator<T> row_iterator;

  //! A const row iterator.
  typedef any_row_iterator<const T> const_row_iterator;

  //! A (non const) element iterator.
  typedef typename DB_Row<T>::iterator element_iterator;

  //! A const element iterator.
  typedef typename DB_Row<T>::const_iterator const_element_iterator;

public:
  //! Returns the maximum number of rows of a OR_Matrix.
  static dimension_type max_num_rows();

  //! Builds a matrix with specified dimensions.
  /*!
    \param space_dim
    The space dimension of the matrix that will be created.

    This constructor creates a matrix with \p 2*space_dim rows.
    Each element is initialized to plus infinity.
  */
  OR_Matrix(dimension_type space_dim);

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

  //! Constructs a conservative approximation of \p y.
  template <typename U>
  explicit OR_Matrix(const OR_Matrix<U>& y);

  //! Destructor.
  ~OR_Matrix();

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

private:
  template <typename U> friend class OR_Matrix;

  //! Contains the rows of the matrix.
  /*!
    A DB_Row which contains the rows of the OR_Matrix
    inserting each successive row to the end of the vec.
    To contain all the elements of OR_Matrix the size of the DB_Row
    is 2*n*(n+1), where the n is the characteristic parameter of
    OR_Matrix.
  */
  DB_Row<T> vec;

  //! Contains the dimension of the space of the matrix.
  dimension_type space_dim;

  //! Contains the capacity of \p vec.
  dimension_type vec_capacity;

  //! Private and not implemented: default construction is not allowed.
  OR_Matrix();

  /*! \brief
    Returns the index into <CODE>vec</CODE> of the first element
    of the row of index \p k.
  */
  static dimension_type row_first_element_index(dimension_type k);

public:
  //! Returns the size of the row of index \p k.
  static dimension_type row_size(dimension_type k);

  //! Swaps \p *this with \p y.
  void swap(OR_Matrix& y);


  //! Makes the matrix grow by adding more space dimensions.
  /*!
    \param new_dim
    The new dimension of the resized matrix.

    Adds new rows of right dimension to the end if
    there is enough capacity; otherwise, creates a new matrix,
    with the specified dimension, copying the old elements
    in the upper part of the new matrix, which is
    then assigned to \p *this.
    Each new element is initialized to plus infinity.
  */
  void grow(dimension_type new_dim);

  //! Makes the matrix shrink by removing the last space dimensions.
  /*!
    \param new_dim
    The new dimension of the resized matrix.

    Erases from matrix to the end the rows with index
    greater than 2*new_dim-1.
  */
  void shrink(dimension_type new_dim);

  //! Resizes the matrix without worrying about the old contents.
  /*!
    \param new_dim
    The new dimension of the resized matrix.

    If the new dimension is greater than the old one, it adds new rows
    of right dimension to the end if there is enough capacity; otherwise,
    it creates a new matrix, with the specified dimension, which is
    then assigned to \p *this.
    If the new dimension is less than the old one, it erase from the matrix
    the rows having index greater than 2*new_dim-1
  */
  void resize_no_copy(dimension_type new_dim);

  //! Returns the space-dimension of the matrix.
  dimension_type space_dimension() const;

  //! 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.
  row_reference_type operator[](dimension_type k);

  //! Returns a constant reference to the \p k-th row of the matrix.
  const_row_reference_type operator[](dimension_type k) const;
  //@}


  /*! \brief
    Returns an iterator pointing to the first row,
    if \p *this is not empty;
    otherwise, returns the past-the-end const_iterator.
  */
  row_iterator row_begin();

  //! Returns the past-the-end const_iterator.
  row_iterator row_end();

  /*! \brief
    Returns a const row iterator pointing to the first row,
    if \p *this is not empty;
    otherwise, returns the past-the-end const_iterator.
  */
  const_row_iterator row_begin() const;

  //! Returns the past-the-end const row iterator.
  const_row_iterator row_end() const;

  /*! \brief
    Returns an iterator pointing to the first element,
    if \p *this is not empty;
    otherwise, returns the past-the-end const_iterator.
  */
  element_iterator element_begin();

  //! Returns the past-the-end const_iterator.
  element_iterator element_end();

  /*! \brief
    Returns a const element iterator pointing to the first element,
    if \p *this is not empty;
    otherwise, returns the past-the-end const_iterator.
  */
  const_element_iterator element_begin() const;

  //! Returns the past-the-end const element iterator.
  const_element_iterator element_end() const;

  //! Clears the matrix deallocating all its rows.
  void clear();

  PPL_OUTPUT_DECLARATIONS

  /*! \brief
    Loads from \p s an ASCII representation (as produced by
    ascii_dump(std::ostream&) const) 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;

  friend bool operator==<T>(const OR_Matrix<T>& x, const OR_Matrix<T>& y);

  //! 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::OR_Matrix */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename T>
void swap(Parma_Polyhedra_Library::OR_Matrix<T>& x,
	  Parma_Polyhedra_Library::OR_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 different.
/*! \relates OR_Matrix */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename T>
bool operator!=(const OR_Matrix<T>& x, const OR_Matrix<T>& y);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Computes the rectilinear (or Manhattan) distance between \p x and \p y.
/*! \relates OR_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 // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename Temp, typename To, typename T>
bool rectilinear_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
				 const OR_Matrix<T>& x,
				 const OR_Matrix<T>& y,
				 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 OR_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 // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename Temp, typename To, typename T>
bool euclidean_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			       const OR_Matrix<T>& x,
			       const OR_Matrix<T>& y,
			       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 OR_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 // defined(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 OR_Matrix<T>& x,
				 const OR_Matrix<T>& y,
				 Rounding_Dir dir,
				 Temp& tmp0,
				 Temp& tmp1,
				 Temp& tmp2);

} // namespace Parma_Polyhedra_Library

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


/* Automatically generated from PPL source file ../src/OR_Matrix.inlines.hh line 31. */
#include <cassert>
#include <algorithm>
/* Automatically generated from PPL source file ../src/OR_Matrix.inlines.hh line 34. */

namespace Parma_Polyhedra_Library {

template <typename T>
inline dimension_type
OR_Matrix<T>::row_first_element_index(const dimension_type k) {
  return ((k+1)*(k+1))/2;
}

template <typename T>
inline dimension_type
OR_Matrix<T>::row_size(const dimension_type k) {
  return k + 2 - k%2;
}

#if PPL_OR_MATRIX_EXTRA_DEBUG

template <typename T>
template <typename U>
inline dimension_type
OR_Matrix<T>::Pseudo_Row<U>::size() const {
  return size_;
}

#endif // PPL_OR_MATRIX_EXTRA_DEBUG

template <typename T>
template <typename U>
inline
OR_Matrix<T>::Pseudo_Row<U>::Pseudo_Row()
  : first(0)
#if PPL_OR_MATRIX_EXTRA_DEBUG
  , size_(0)
#endif
{
}

template <typename T>
template <typename U>
inline
OR_Matrix<T>::Pseudo_Row<U>::Pseudo_Row(U& y
#if PPL_OR_MATRIX_EXTRA_DEBUG
		, dimension_type s
#endif
		)
  : first(&y)
#if PPL_OR_MATRIX_EXTRA_DEBUG
  , size_(s)
#endif
{
}

template <typename T>
template <typename U>
template <typename V>
inline
OR_Matrix<T>::Pseudo_Row<U>::Pseudo_Row(const Pseudo_Row<V>& y)
  : first(y.first)
#if PPL_OR_MATRIX_EXTRA_DEBUG
    , size_(y.size_)
#endif
{
}

template <typename T>
template <typename U>
inline OR_Matrix<T>::Pseudo_Row<U>&
OR_Matrix<T>::Pseudo_Row<U>::operator=(const Pseudo_Row& y) {
  first = y.first;
#if PPL_OR_MATRIX_EXTRA_DEBUG
  size_ = y.size_;
#endif
  return *this;
}

template <typename T>
template <typename U>
inline
OR_Matrix<T>::Pseudo_Row<U>::~Pseudo_Row() {
}

template <typename T>
template <typename U>
inline U&
OR_Matrix<T>::Pseudo_Row<U>::operator[](const dimension_type k) const {
#if PPL_OR_MATRIX_EXTRA_DEBUG
  assert(k < size_);
#endif
  return *(first + k);
}

template <typename T>
template <typename U>
inline
OR_Matrix<T>::any_row_iterator<U>
::any_row_iterator(const dimension_type n_rows)
  : value(),
    e(n_rows)
    // Field `i' is intentionally not initialized here.
{
#if PPL_OR_MATRIX_EXTRA_DEBUG
  // Turn `value' into a valid object.
  value.size_ = OR_Matrix::row_size(e);
#endif
}

template <typename T>
template <typename U>
inline
OR_Matrix<T>::any_row_iterator<U>::any_row_iterator(U& base)
  :  value(base
#if PPL_OR_MATRIX_EXTRA_DEBUG
	   , OR_Matrix<T>::row_size(0)
#endif
	   ),
     e(0),
     i(0) {
}

template <typename T>
template <typename U>
template <typename V>
inline
OR_Matrix<T>::any_row_iterator<U>
::any_row_iterator(const any_row_iterator<V>& y)
  : value(y.value),
    e(y.e),
    i(y.i) {
}

template <typename T>
template <typename U>
template <typename V>
inline typename OR_Matrix<T>::template any_row_iterator<U>&
OR_Matrix<T>::any_row_iterator<U>::operator=(const any_row_iterator<V>& y) {
  value = y.value;
  e = y.e;
  i = y.i;
  return *this;
}

template <typename T>
template <typename U>
inline typename OR_Matrix<T>::template any_row_iterator<U>::reference
OR_Matrix<T>::any_row_iterator<U>::operator*() const {
  return value;
}

template <typename T>
template <typename U>
inline typename OR_Matrix<T>::template any_row_iterator<U>::pointer
OR_Matrix<T>::any_row_iterator<U>::operator->() const {
  return &value;
}

template <typename T>
template <typename U>
inline typename OR_Matrix<T>::template any_row_iterator<U>&
OR_Matrix<T>::any_row_iterator<U>::operator++() {
  ++e;
  dimension_type increment = e;
  if (e % 2 != 0)
    ++increment;
#if PPL_OR_MATRIX_EXTRA_DEBUG
  else {
    value.size_ += 2;
  }
#endif
  i += increment;
  value.first += increment;
  return *this;
}

template <typename T>
template <typename U>
inline typename OR_Matrix<T>::template any_row_iterator<U>
OR_Matrix<T>::any_row_iterator<U>::operator++(int) {
  any_row_iterator old = *this;
  ++(*this);
  return old;
}

template <typename T>
template <typename U>
inline typename OR_Matrix<T>::template any_row_iterator<U>&
OR_Matrix<T>::any_row_iterator<U>::operator--() {
  dimension_type decrement = e + 1;
  --e;
  if (e % 2 != 0) {
    ++decrement;
#if PPL_OR_MATRIX_EXTRA_DEBUG
    value.size_ -= 2;
#endif
  }
  i -= decrement;
  value.first -= decrement;
  return *this;
}

template <typename T>
template <typename U>
inline typename OR_Matrix<T>::template any_row_iterator<U>
OR_Matrix<T>::any_row_iterator<U>::operator--(int) {
  any_row_iterator old = *this;
  --(*this);
  return old;
}

template <typename T>
template <typename U>
inline typename OR_Matrix<T>::template any_row_iterator<U>&
OR_Matrix<T>::any_row_iterator<U>::operator+=(const difference_type m) {
  difference_type increment = m + m*m/2 + m*e;
  if (e % 2 == 0 && m % 2 != 0)
    ++increment;
  e += m;
  i += increment;
  value.first += increment;
#if PPL_OR_MATRIX_EXTRA_DEBUG
  value.size_ += (m - m%2);
#endif
  return *this;
}

template <typename T>
template <typename U>
inline typename OR_Matrix<T>::template any_row_iterator<U>&
OR_Matrix<T>::any_row_iterator<U>::operator-=(difference_type m) {
  return *this += -m;
}

template <typename T>
template <typename U>
inline typename OR_Matrix<T>::template any_row_iterator<U>::difference_type
OR_Matrix<T>::any_row_iterator<U>::operator-(const any_row_iterator& y) const {
  return e - y.e;
}

template <typename T>
template <typename U>
inline typename OR_Matrix<T>::template any_row_iterator<U>
OR_Matrix<T>::any_row_iterator<U>::operator+(difference_type m) const {
  any_row_iterator r = *this;
  r += m;
  return r;
}

template <typename T>
template <typename U>
inline typename OR_Matrix<T>::template any_row_iterator<U>
OR_Matrix<T>::any_row_iterator<U>::operator-(const difference_type m) const {
  any_row_iterator r = *this;
  r -= m;
  return r;
}

template <typename T>
template <typename U>
inline bool
OR_Matrix<T>::any_row_iterator<U>
::operator==(const any_row_iterator& y) const {
  return e == y.e;
}

template <typename T>
template <typename U>
inline bool
OR_Matrix<T>::any_row_iterator<U>
::operator!=(const any_row_iterator& y) const {
  return e != y.e;
}

template <typename T>
template <typename U>
inline bool
OR_Matrix<T>::any_row_iterator<U>::operator<(const any_row_iterator& y) const {
  return e < y.e;
}

template <typename T>
template <typename U>
inline bool
OR_Matrix<T>::any_row_iterator<U>
::operator<=(const any_row_iterator& y) const {
  return e <= y.e;
}

template <typename T>
template <typename U>
inline bool
OR_Matrix<T>::any_row_iterator<U>::operator>(const any_row_iterator& y) const {
  return e > y.e;
}

template <typename T>
template <typename U>
inline bool
OR_Matrix<T>::any_row_iterator<U>
::operator>=(const any_row_iterator& y) const {
  return e >= y.e;
}

template <typename T>
template <typename U>
inline dimension_type
OR_Matrix<T>::any_row_iterator<U>::row_size() const {
  return OR_Matrix::row_size(e);
}

template <typename T>
template <typename U>
inline dimension_type
OR_Matrix<T>::any_row_iterator<U>::index() const {
  return e;
}

template <typename T>
inline typename OR_Matrix<T>::row_iterator
OR_Matrix<T>::row_begin() {
  return num_rows() == 0 ? row_iterator(0) : row_iterator(vec[0]);
}

template <typename T>
inline typename OR_Matrix<T>::row_iterator
OR_Matrix<T>::row_end() {
  return row_iterator(num_rows());
}

template <typename T>
inline typename OR_Matrix<T>::const_row_iterator
OR_Matrix<T>::row_begin() const {
  return num_rows() == 0 ? const_row_iterator(0) : const_row_iterator(vec[0]);
}

template <typename T>
inline typename OR_Matrix<T>::const_row_iterator
OR_Matrix<T>::row_end() const {
  return const_row_iterator(num_rows());
}

template <typename T>
inline typename OR_Matrix<T>::element_iterator
OR_Matrix<T>::element_begin() {
  return vec.begin();
}

template <typename T>
inline typename OR_Matrix<T>::element_iterator
OR_Matrix<T>::element_end() {
  return vec.end();
}

template <typename T>
inline typename OR_Matrix<T>::const_element_iterator
OR_Matrix<T>::element_begin() const {
  return vec.begin();
}

template <typename T>
inline typename OR_Matrix<T>::const_element_iterator
OR_Matrix<T>::element_end() const {
  return vec.end();
}

template <typename T>
inline void
OR_Matrix<T>::swap(OR_Matrix& y) {
  std::swap(vec, y.vec);
  std::swap(space_dim, y.space_dim);
  std::swap(vec_capacity, y.vec_capacity);
}

//! Returns the integer square root of \p x.
inline unsigned long
isqrt(unsigned long x) {
  unsigned long r = 0;
  for (unsigned long t = 0x40000000; t; t >>= 2) {
    unsigned long s = r + t;
    if (s <= x) {
      x -= s;
      r = s + t;
    }
    r >>= 1;
  }
  return r;
}

template <typename T>
inline dimension_type
OR_Matrix<T>::max_num_rows() {
  // Compute the maximum number of rows that are contained in a DB_Row
  // that allocates a pseudo-triangular matrix.
  dimension_type k = isqrt(2*DB_Row<T>::max_size() + 1);
  return (k - 1) - (k - 1)%2;
}

template <typename T>
inline memory_size_type
OR_Matrix<T>::total_memory_in_bytes() const {
  return sizeof(*this) + external_memory_in_bytes();
}

template <typename T>
inline
OR_Matrix<T>::OR_Matrix(const dimension_type dim)
  : vec(2*dim*(dim+1)),
    space_dim(dim),
    vec_capacity(vec.size()) {
}

template <typename T>
inline
OR_Matrix<T>::~OR_Matrix() {
}

template <typename T>
inline typename OR_Matrix<T>::row_reference_type
OR_Matrix<T>::operator[](dimension_type k) {
  return row_reference_type(vec[row_first_element_index(k)]
#if PPL_OR_MATRIX_EXTRA_DEBUG
			    , row_size(k)
#endif
			    );
}

template <typename T>
inline typename OR_Matrix<T>::const_row_reference_type
OR_Matrix<T>::operator[](dimension_type k) const {
  return const_row_reference_type(vec[row_first_element_index(k)]
#if PPL_OR_MATRIX_EXTRA_DEBUG
				  , row_size(k)
#endif
				  );
}

template <typename T>
inline dimension_type
OR_Matrix<T>::space_dimension() const {
  return space_dim;
}

template <typename T>
inline dimension_type
OR_Matrix<T>::num_rows() const {
  return 2*space_dimension();
}

template <typename T>
inline void
OR_Matrix<T>::clear() {
  OR_Matrix<T>(0).swap(*this);
}

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \relates OR_Matrix */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename T>
inline bool
operator==(const OR_Matrix<T>& x, const OR_Matrix<T>& y) {
  return x.space_dim == y.space_dim && x.vec == y.vec;
}

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \relates OR_Matrix */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename T>
inline bool
operator!=(const OR_Matrix<T>& x, const OR_Matrix<T>& y) {
  return !(x == y);
}

template <typename T>
inline
OR_Matrix<T>::OR_Matrix(const OR_Matrix& y)
  : vec(y.vec),
    space_dim(y.space_dim),
    vec_capacity(compute_capacity(y.vec.size(),
                                  DB_Row<T>::max_size())) {
}

template <typename T>
template <typename U>
inline
OR_Matrix<T>::OR_Matrix(const OR_Matrix<U>& y)
  : vec(),
    space_dim(y.space_dim),
    vec_capacity(compute_capacity(y.vec.size(),
                                  DB_Row<T>::max_size())) {
  vec.construct_upward_approximation(y.vec, vec_capacity);
  assert(OK());
}

template <typename T>
inline OR_Matrix<T>&
OR_Matrix<T>::operator=(const OR_Matrix& y) {
  vec = y.vec;
  space_dim = y.space_dim;
  vec_capacity = compute_capacity(y.vec.size(), DB_Row<T>::max_size());
  return *this;
}

template <typename T>
inline void
OR_Matrix<T>::grow(const dimension_type new_dim) {
  assert(new_dim >= space_dim);
  if (new_dim > space_dim) {
    const dimension_type new_size = 2*new_dim*(new_dim + 1);
    if (new_size <= vec_capacity) {
      // We can recycle the old vec.
      vec.expand_within_capacity(new_size);
      space_dim = new_dim;
    }
    else {
      // We cannot recycle the old vec.
      OR_Matrix<T> new_matrix(new_dim);
      element_iterator j = new_matrix.element_begin();
      for (element_iterator i = element_begin(),
	     mend = element_end(); i != mend; ++i, ++j)
	assign_or_swap(*j, *i);
      swap(new_matrix);
    }
  }
}

template <typename T>
inline void
OR_Matrix<T>::shrink(const dimension_type new_dim) {
  assert(new_dim <= space_dim);
  const dimension_type new_size = 2*new_dim*(new_dim + 1);
  vec.shrink(new_size);
  space_dim = new_dim;
}

template <typename T>
inline void
OR_Matrix<T>::resize_no_copy(const dimension_type new_dim) {
  if (new_dim > space_dim) {
    const dimension_type new_size = 2*new_dim*(new_dim + 1);
    if (new_size <= vec_capacity) {
      // We can recycle the old vec.
      vec.expand_within_capacity(new_size);
      space_dim = new_dim;
    }
    else {
      // We cannot recycle the old vec.
      OR_Matrix<T> new_matrix(new_dim);
      swap(new_matrix);
    }
  }
  else if (new_dim < space_dim)
    shrink(new_dim);
}

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \relates OR_Matrix */
#endif // defined(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 OR_Matrix<T>& x,
		    const OR_Matrix<T>& y,
		    const Rounding_Dir dir,
		    Temp& tmp0,
		    Temp& tmp1,
		    Temp& tmp2) {
  if (x.num_rows() != y.num_rows())
    return false;
  assign_r(tmp0, 0, ROUND_NOT_NEEDED);
  for (typename OR_Matrix<T>::const_element_iterator
	 i = x.element_begin(), j = y.element_begin(),
	 mat_end = x.element_end(); i != mat_end; ++i, ++j) {
    const T& x_i = *i;
    const T& y_i = *j;
    if (is_plus_infinity(x_i)) {
      if (is_plus_infinity(y_i))
	continue;
      else {
      pinf:
	assign_r(r, PLUS_INFINITY, ROUND_NOT_NEEDED);
	return true;
      }
    }
    else if (is_plus_infinity(y_i))
      goto pinf;

    const Temp* tmp1p;
    const Temp* tmp2p;
    if (x_i > y_i) {
      maybe_assign(tmp1p, tmp1, x_i, dir);
      maybe_assign(tmp2p, tmp2, y_i, inverse(dir));
    }
    else {
      maybe_assign(tmp1p, tmp1, y_i, dir);
      maybe_assign(tmp2p, tmp2, x_i, inverse(dir));
    }
    sub_assign_r(tmp1, *tmp1p, *tmp2p, dir);
    assert(sgn(tmp1) >= 0);
    Specialization::combine(tmp0, tmp1, dir);
  }

  Specialization::finalize(tmp0, dir);
  assign_r(r, tmp0, dir);
  return true;
}


#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \relates OR_Matrix */
#endif // defined(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 OR_Matrix<T>& x,
			    const OR_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);
}

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \relates OR_Matrix */
#endif // defined(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 OR_Matrix<T>& x,
			  const OR_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);
}

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \relates OR_Matrix */
#endif // defined(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 OR_Matrix<T>& x,
			   const OR_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);
}

} // namespace Parma_Polyhedra_Library

namespace std {

/*! \relates Parma_Polyhedra_Library::OR_Matrix */
template <typename T>
inline void
swap(Parma_Polyhedra_Library::OR_Matrix<T>& x,
     Parma_Polyhedra_Library::OR_Matrix<T>& y) {
  x.swap(y);
}

} // namespace std


/* Automatically generated from PPL source file ../src/OR_Matrix.templates.hh line 1. */
/* OR_Matrix class implementation: non-inline template functions.
*/


#include <iostream>

namespace Parma_Polyhedra_Library {

template <typename T>
memory_size_type
OR_Matrix<T>::external_memory_in_bytes() const{
  return vec.external_memory_in_bytes();
}

template <typename T>
bool
OR_Matrix<T>::OK() const {
#ifndef NDEBUG
  using std::endl;
  using std::cerr;
#endif
  // The right number of cells should be in use.
  const dimension_type dim = space_dimension();
  if (vec.size() != 2*dim*(dim + 1)) {
#ifndef NDEBUG
    cerr << "OR_Matrix has a wrong number of cells:\n"
	 << "vec.size() is " << vec.size()
	 << ", expected size is " << 2*dim*(dim+1) << "!\n";
#endif
    return false;
  }

  // The underlying DB_Row should be OK.
  if (!vec.OK(vec.size(), vec_capacity))
    return false;

  // All checks passed.
  return true;
}

template <typename T>
void
OR_Matrix<T>::ascii_dump(std::ostream& s) const {
  const OR_Matrix<T>& x = *this;
  const char separator = ' ';
  dimension_type space = x.space_dimension();
  s << space << separator << "\n";
  for (const_row_iterator i = x.row_begin(),
	 x_row_end = x.row_end(); i != x_row_end; ++i) {
    const_row_reference_type r = *i;
    dimension_type rs = i.row_size();
    for (dimension_type j = 0; j < rs; ++j) {
      using namespace IO_Operators;
      s << r[j] << separator;
    }
    s << "\n";
  }
}

PPL_OUTPUT_TEMPLATE_DEFINITIONS(T, OR_Matrix<T>)

template <typename T>
bool
OR_Matrix<T>::ascii_load(std::istream& s) {
  dimension_type space;
  if (!(s >> space))
    return false;
  resize_no_copy(space);
  for (row_iterator i = row_begin(),
	 this_row_end = row_end(); i != this_row_end; ++i) {
    row_reference_type r_i = *i;
    const dimension_type rs = i.row_size();
    for (dimension_type j = 0; j < rs; ++j) {
      Result r = input(r_i[j], s, ROUND_CHECK);
      if (r != V_EQ || is_minus_infinity(r_i[j]))
	return false;
    }
  }
  assert(OK());
  return true;
}

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \relates Parma_Polyhedra_Library::OR_Matrix */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename T>
std::ostream&
IO_Operators::operator<<(std::ostream& s, const OR_Matrix<T>& m) {
  for (typename OR_Matrix<T>::const_row_iterator m_iter = m.row_begin(),
	 m_end = m.row_end(); m_iter != m_end; ++m_iter) {
    typename OR_Matrix<T>::const_row_reference_type r_m = *m_iter;
    const dimension_type mr_size = m_iter.row_size();
    for (dimension_type j = 0; j < mr_size; ++j)
      s << r_m[j] << " ";
    s << "\n";
  }
  return s;
}

} // namespace Parma_Polyhedra_Library

/* Automatically generated from PPL source file ../src/OR_Matrix.defs.hh line 606. */

/* Automatically generated from PPL source file ../src/Octagonal_Shape.defs.hh line 45. */
#include <vector>
#include <cstddef>
#include <climits>
#include <iosfwd>

namespace Parma_Polyhedra_Library {

namespace IO_Operators {

//! Output operator.
/*! \relates Parma_Polyhedra_Library::Octagonal_Shape
  Writes a textual representation of \p oct on \p s:
  <CODE>false</CODE> is written if \p oct is an empty polyhedron;
  <CODE>true</CODE> is written if \p oct is a universe polyhedron;
  a system of constraints defining \p oct is written otherwise,
  all constraints separated by ", ".
*/
template <typename T>
std::ostream&
operator<<(std::ostream& s, const Octagonal_Shape<T>& oct);

} // namespace IO_Operators

/*! \brief
  Returns <CODE>true</CODE> if and only if \p x and \p y are the same octagon.

  \relates Octagonal_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 Octagonal_Shape<T>& x, const Octagonal_Shape<T>& y);

/*! \brief
  Returns <CODE>true</CODE> if and only if \p x and \p y are different shapes.

  \relates Octagonal_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 Octagonal_Shape<T>& x, const Octagonal_Shape<T>& y);

//! Computes the rectilinear (or Manhattan) distance between \p x and \p y.
/*! \relates Octagonal_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 Octagonal_Shape<T>& x,
                                 const Octagonal_Shape<T>& y,
                                 Rounding_Dir dir);

//! Computes the rectilinear (or Manhattan) distance between \p x and \p y.
/*! \relates Octagonal_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 Octagonal_Shape<T>& x,
                                 const Octagonal_Shape<T>& y,
                                 Rounding_Dir dir);

//! Computes the rectilinear (or Manhattan) distance between \p x and \p y.
/*! \relates Octagonal_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 Octagonal_Shape<T>& x,
                                 const Octagonal_Shape<T>& y,
                                 Rounding_Dir dir,
                                 Temp& tmp0,
                                 Temp& tmp1,
                                 Temp& tmp2);

//! Computes the euclidean distance between \p x and \p y.
/*! \relates Octagonal_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 Octagonal_Shape<T>& x,
                               const Octagonal_Shape<T>& y,
                               Rounding_Dir dir);

//! Computes the euclidean distance between \p x and \p y.
/*! \relates Octagonal_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 Octagonal_Shape<T>& x,
                               const Octagonal_Shape<T>& y,
                               Rounding_Dir dir);

//! Computes the euclidean distance between \p x and \p y.
/*! \relates Octagonal_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 Octagonal_Shape<T>& x,
                               const Octagonal_Shape<T>& y,
                               Rounding_Dir dir,
                               Temp& tmp0,
                               Temp& tmp1,
                               Temp& tmp2);

//! Computes the \f$L_\infty\f$ distance between \p x and \p y.
/*! \relates Octagonal_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 Octagonal_Shape<T>& x,
                                const Octagonal_Shape<T>& y,
                                Rounding_Dir dir);

//! Computes the \f$L_\infty\f$ distance between \p x and \p y.
/*! \relates Octagonal_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 Octagonal_Shape<T>& x,
                                const Octagonal_Shape<T>& y,
                                Rounding_Dir dir);

//! Computes the \f$L_\infty\f$ distance between \p x and \p y.
/*! \relates Octagonal_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 Octagonal_Shape<T>& x,
                                const Octagonal_Shape<T>& y,
                                Rounding_Dir dir,
                                Temp& tmp0,
                                Temp& tmp1,
                                Temp& tmp2);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Decodes the constraint \p c as an octagonal difference.
/*! \relates Octagonal_Shape
  \return
  <CODE>true</CODE> if the constraint \p c is an octagonal 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.

  \param c_term
  If <CODE>true</CODE> is returned and if \p c_num_vars is not set to 0,
  then it will be set to the right value of the inhomogeneous term
  of \p c.
*/
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
bool extract_octagonal_difference(const Constraint& c,
                                  dimension_type c_space_dim,
                                  dimension_type& c_num_vars,
                                  dimension_type& c_first_var,
                                  dimension_type& c_second_var,
                                  Coefficient& c_coeff,
                                  Coefficient& c_term);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Returns the index coherent to \p i.
/*! \relates Octagonal_Shape */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
dimension_type coherent_index(dimension_type i);

} // namespace Parma_Polyhedra_Library

//! An octagonal shape.
/*! \ingroup PPL_CXX_interface
  The class template Octagonal_Shape<T> allows for the efficient
  representation of a restricted kind of <EM>topologically closed</EM>
  convex polyhedra called <EM>octagonal shapes</EM> (OSs, for short).
  The name comes from the fact that, in a vector space of dimension 2,
  bounded OSs are polygons with at most eight sides.
  The closed affine half-spaces that characterize the OS can be expressed
  by constraints of the form
  \f[
    ax_i + bx_j \leq k
  \f]
  where \f$a, b \in \{-1, 0, 1\}\f$ and \f$k\f$ is a rational number,
  which are called <EM>octagonal constraints</EM>.

  Based on the class template type parameter \p T, a family of extended
  numbers is built and used to approximate the inhomogeneous term of
  octagonal constraints. 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 OSs is meant to be as similar as possible to
  the one developed for the polyhedron class C_Polyhedron.

  The OS domain <EM>optimally supports</EM>:
    - tautological and inconsistent constraints and congruences;
    - octagonal constraints;
    - non-proper congruences (i.e., equalities) that are expressible
      as octagonal constraints.

  Depending on the method, using a constraint or congruence that is not
  optimally supported by the domain will either raise an exception or
  result in a (possibly non-optimal) upward approximation.

  A constraint is octagonal if it has the form
    \f[
      \pm a_i x_i \pm 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 octagonal Constraint object
  will be mapped into a \e correct and \e optimal approximation that,
  depending on the expressive power of the chosen template argument \p T,
  may loose some precision.
  Also note that strict constraints are not octagonal.

  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, depending from the context, a Constraint object
  encoding \f$3x - y \leq 1\f$ will be either upward approximated
  (e.g., by safely ignoring it) or it will cause an exception.

  In the following examples it is assumed that the type argument \p T
  is one of the possible instances listed above and that variables
  \c x, \c y and \c z 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 an OS 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 <= 3);
    cs.insert(y >= 0);
    cs.insert(y <= 3);
    cs.insert(z >= 0);
    cs.insert(z <= 3);
    Octagonal_Shape<T> oct(cs);
  \endcode
  In contrast, the following code will raise an exception,
  since constraints 7, 8, and 9 are not octagonal:
  \code
    Constraint_System cs;
    cs.insert(x >= 0);
    cs.insert(x <= 3);
    cs.insert(y >= 0);
    cs.insert(y <= 3);
    cs.insert(z >= 0);
    cs.insert(z <= 3);
    cs.insert(x - 3*y <= 5);    // (7)
    cs.insert(x - y + z <= 5);  // (8)
    cs.insert(x + y + z <= 5);  // (9)
    Octagonal_Shape<T> oct(cs);
  \endcode
*/
template <typename T>
class Parma_Polyhedra_Library::Octagonal_Shape {
private:
  /*! \brief
    The (extended) numeric type of the inhomogeneous term of
    the inequalities defining an OS.
  */
#ifndef NDEBUG
  typedef Checked_Number<T, Extended_Number_Policy> N;
#else
  typedef Checked_Number<T, WRD_Extended_Number_Policy> N;
#endif

public:
  //! The numeric base type upon which OSs are built.
  typedef T coefficient_type_base;

  /*! \brief
    The (extended) numeric type of the inhomogeneous term of the
    inequalities defining an OS.
  */
  typedef N coefficient_type;

  //! Returns the maximum space dimension that an OS can handle.
  static dimension_type max_space_dimension();

  /*! \brief
    Returns false indicating that this domain cannot recycle constraints
  */
  static bool can_recycle_constraint_systems();

  /*! \brief
    Returns false indicating that this domain cannot recycle congruences
  */
  static bool can_recycle_congruence_systems();

  //! \name Constructors, Assignment, Swap and Destructor
  //@{

  //! Builds an universe or empty OS of the specified space dimension.
  /*!
    \param num_dimensions
    The number of dimensions of the vector space enclosing the OS;

    \param kind
    Specifies whether the universe or the empty OS has to be built.
  */
  explicit Octagonal_Shape(dimension_type num_dimensions = 0,
                           Degenerate_Element kind = UNIVERSE);

  //! Ordinary copy-constructor.
  /*!
    The complexity argument is ignored.
  */
  Octagonal_Shape(const Octagonal_Shape& x,
                  Complexity_Class complexity = ANY_COMPLEXITY);

  //! Builds a conservative, upward approximation of \p y.
  /*!
    The complexity argument is ignored.
  */
  template <typename U>
  explicit Octagonal_Shape(const Octagonal_Shape<U>& y,
                           Complexity_Class complexity = ANY_COMPLEXITY);

  //! Builds an OS from the system of constraints \p cs.
  /*!
    The OS inherits the space dimension of \p cs.

    \param cs
    A system of constraints: constraints that are not
    \ref Octagonal_Shapes "octagonal constraints"
    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.
  */
  explicit Octagonal_Shape(const Constraint_System& cs);

  //! Builds an OS from a system of congruences.
  /*!
    The OS inherits the space dimension of \p cgs

    \param cgs
    A system of congruences: some elements may be safely ignored.
  */
  explicit Octagonal_Shape(const Congruence_System& cgs);

  //! Builds an OS from the system of generators \p gs.
  /*!
    Builds the smallest OS containing the polyhedron defined by \p gs.
    The OS inherits the space dimension of \p gs.

    \exception std::invalid_argument
    Thrown if the system of generators is not empty but has no points.
  */
  explicit Octagonal_Shape(const Generator_System& gs);

  //! Builds an OS from the polyhedron \p ph.
  /*!
    Builds an OS 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 OS built is the
    smallest one containing \p ph.
  */
  explicit Octagonal_Shape(const Polyhedron& ph,
                           Complexity_Class complexity = ANY_COMPLEXITY);

  //! Builds an OS out of a box.
  /*!
    The OS inherits the space dimension of the box.
    The built OS is the most precise OS that includes the box.

    \param box
    The box representing the BDS to be built.

    \param complexity
    This argument is ignored as the algorithm used has
    polynomial complexity.

    \exception std::length_error
    Thrown if the space dimension of \p box exceeds the maximum
    allowed space dimension.
  */
  template <typename Interval>
  explicit Octagonal_Shape(const Box<Interval>& box,
                           Complexity_Class complexity = ANY_COMPLEXITY);

  //! Builds an OS that approximates a grid.
  /*!
    The OS inherits the space dimension of the grid.
    The built OS is the most precise OS that includes the grid.

    \param grid
    The grid used to build the OS.

    \param complexity
    This argument is ignored as the algorithm used has
    polynomial complexity.

    \exception std::length_error
    Thrown if the space dimension of \p grid exceeds the maximum
    allowed space dimension.
  */
  explicit Octagonal_Shape(const Grid& grid,
                           Complexity_Class complexity = ANY_COMPLEXITY);

  //! Builds an OS from a BD shape.
  /*!
    The OS inherits the space dimension of the BD shape.
    The built OS is the most precise OS that includes the BD shape.

    \param bd
    The BD shape used to build the OS.

    \param complexity
    This argument is ignored as the algorithm used has
    polynomial complexity.

    \exception std::length_error
    Thrown if the space dimension of \p bd exceeds the maximum
    allowed space dimension.
  */
  template <typename U>
  explicit Octagonal_Shape(const BD_Shape<U>& bd,
                           Complexity_Class complexity = ANY_COMPLEXITY);

  /*! \brief
    The assignment operator.
    (\p *this and \p y can be dimension-incompatible.)
  */
  Octagonal_Shape& operator=(const Octagonal_Shape& y);

  /*! \brief
    Swaps \p *this with octagon \p y.
    (\p *this and \p y can be dimension-incompatible.)
  */
  void swap(Octagonal_Shape& y);

  //! Destructor.
  ~Octagonal_Shape();

  //@} Constructors, Assignment, Swap and Destructor

  //! \name Member Functions that Do Not Modify the Octagonal_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 the 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 a system of (equality) congruences satisfied by \p *this.
  Congruence_System congruences() const;

  /*! \brief
    Returns a minimal system of (equality) congruences
    satisfied by \p *this with the same affine dimension as \p *this.
  */
  Congruence_System minimized_congruences() 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 Octagonal_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 Octagonal_Shape& y) 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 Octagonal_Shape& y) const;

  /*! \brief
    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.
  */
  Poly_Con_Relation relation_with(const Constraint& c) const;

  /*! \brief
    Returns the relations holding between \p *this and the congruence \p cg.

    \exception std::invalid_argument
    Thrown if \p *this and \p cg are dimension-incompatible.
  */
  Poly_Con_Relation relation_with(const Congruence& cg) const;

  /*! \brief
    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 OS.
  bool is_empty() const;

  //! Returns <CODE>true</CODE> if and only if \p *this is a universe OS.
  bool is_universe() const;

  //! Returns <CODE>true</CODE> if and only if \p *this is discrete.
  bool is_discrete() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this
    is a bounded OS.
  */
  bool is_bounded() 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
    contains (at least) an integer point.
  */
  bool contains_integer_point() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p var is constrained in
    \p *this.

    \exception std::invalid_argument
    Thrown if \p var is not a space dimension of \p *this.
  */
  bool constrains(Variable var) 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 g
    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 g are left untouched.
  */
  bool maximize(const Linear_Expression& expr,
                Coefficient& sup_n, Coefficient& sup_d, bool& maximum,
                Generator& g) 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 g
    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 g are left untouched.
  */
  bool minimize(const Linear_Expression& expr,
                Coefficient& inf_n, Coefficient& inf_d, bool& minimum,
                Generator& g) const;

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

  //@} Member Functions that Do Not Modify the Octagonal_Shape

  //! \name Space-Dimension Preserving Member Functions that May Modify the Octagonal_Shape
  //@{

  /*! \brief
    Adds a copy of constraint \p c to the system of constraints
    defining \p *this.

    \param c
    The constraint to be added.

    \exception std::invalid_argument
    Thrown if \p *this and constraint \p c are dimension-incompatible,
    or \p c is not optimally supported by the OS domain.
  */
  void add_constraint(const Constraint& c);

  /*! \brief
    Adds the constraints in \p cs to the system of constraints
    defining \p *this.

    \param  cs
    The constraints that will be added.

    \exception std::invalid_argument
    Thrown if \p *this and \p cs are dimension-incompatible,
    or \p cs contains a constraint which is not optimally supported
    by the OS domain.
  */
  void add_constraints(const Constraint_System& cs);

  /*! \brief
    Adds the constraints in \p cs to the system of constraints
    of \p *this.

    \param cs
    The constraint system to be added to \p *this.  The constraints in
    \p cs may be recycled.

    \exception std::invalid_argument
    Thrown if \p *this and \p cs are dimension-incompatible,
    or \p cs contains a constraint which is not optimally supported
    by the OS domain.

    \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 to \p *this a constraint equivalent to the congruence \p cg.

    \param cg
    The congruence to be added.

    \exception std::invalid_argument
    Thrown if \p *this and congruence \p cg are dimension-incompatible,
    or \p cg is not optimally supported by the OS domain.
  */
  void add_congruence(const Congruence& cg);

  /*! \brief
    Adds to \p *this constraints equivalent to the congruences in \p cgs.

    \param cgs
    The congruences to be added.

    \exception std::invalid_argument
    Thrown if \p *this and \p cgs are dimension-incompatible,
    or \p cgs contains a congruence which is not optimally supported
    by the OS domain.
  */
  void add_congruences(const Congruence_System& cgs);

  /*! \brief
    Adds to \p *this constraints equivalent to the congruences in \p cgs.

    \param cgs
    The congruence system to be added to \p *this.  The congruences in
    \p cgs may be recycled.

    \exception std::invalid_argument
    Thrown if \p *this and \p cgs are dimension-incompatible,
    or \p cgs contains a congruence which is not optimally supported
    by the OS domain.

    \warning
    The only assumption that can be made on \p cgs upon successful or
    exceptional return is that it can be safely destroyed.
  */
  void add_recycled_congruences(Congruence_System& cgs);

  /*! \brief
    Uses a copy of constraint \p c to refine the system of octagonal
    constraints defining \p *this.

    \param c
    The constraint. If it is not a octagonal constraint, it will be ignored.

    \exception std::invalid_argument
    Thrown if \p *this and constraint \p c are dimension-incompatible.
  */
  void refine_with_constraint(const Constraint& c);

  /*! \brief
    Uses a copy of congruence \p cg to refine the system of
    octagonal constraints  of \p *this.

    \param cg
    The congruence. If it is not a octagonal equality, it
    will be ignored.

    \exception std::invalid_argument
    Thrown if \p *this and congruence \p cg are dimension-incompatible.
  */
  void refine_with_congruence(const Congruence& cg);

  /*! \brief
    Uses a copy of the constraints in \p cs to refine the system of
    octagonal constraints defining \p *this.

    \param  cs
    The constraint system to be used. Constraints that are not octagonal
    are ignored.

    \exception std::invalid_argument
    Thrown if \p *this and \p cs are dimension-incompatible.
  */
  void refine_with_constraints(const Constraint_System& cs);

  /*! \brief
    Uses a copy of the congruences in \p cgs to refine the system of
    octagonal constraints defining \p *this.

    \param  cgs
    The congruence system to be used. Congruences that are not octagonal
    equalities are ignored.

    \exception std::invalid_argument
    Thrown if \p *this and \p cgs are dimension-incompatible.
  */
  void refine_with_congruences(const Congruence_System& cgs);

  /*! \brief
    Computes the \ref Cylindrification "cylindrification" of \p *this with
    respect to space dimension \p var, assigning the result to \p *this.

    \param var
    The space dimension that will be unconstrained.

    \exception std::invalid_argument
    Thrown if \p var is not a space dimension of \p *this.
  */
  void unconstrain(Variable var);

  /*! \brief
    Computes the \ref Cylindrification "cylindrification" of \p *this with
    respect to the set of space dimensions \p to_be_unconstrained,
    assigning the result to \p *this.

    \param to_be_unconstrained
    The set of space dimension that will be unconstrained.

    \exception std::invalid_argument
    Thrown if \p *this is dimension-incompatible with one of the
    Variable objects contained in \p to_be_removed.
  */
  void unconstrain(const Variables_Set& to_be_unconstrained);

  //! 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 Octagonal_Shape& y);

  /*! \brief
    Assigns to \p *this the smallest OS that contains
    the convex union of \p *this and \p y.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are dimension-incompatible.
  */
  void upper_bound_assign(const Octagonal_Shape& y);

  /*! \brief
    If the upper bound 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 upper_bound_assign_if_exact(const Octagonal_Shape& y);

  /*! \brief
    Assigns to \p *this the smallest octagon containing
    the set difference of \p *this and \p y.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are dimension-incompatible.
  */
  void difference_assign(const Octagonal_Shape& y);

  /*! \brief
    Assigns to \p *this a \ref Meet_Preserving_Simplification
    "meet-preserving simplification" of \p *this with respect to \p y.
    If \c false is returned, then the intersection is empty.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are topology-incompatible or
    dimension-incompatible.
  */
  bool simplify_using_context_assign(const Octagonal_Shape& y);

  /*! \brief
    Assigns to \p *this the \ref affine_relation "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 affine_relation "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 "generalized affine transfer function"
    \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 "generalized affine transfer function"
    \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 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 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 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 relsym is a strict relation symbol.
  */
  void generalized_affine_preimage(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 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 dimension-incompatible.
  */
  void time_elapse_assign(const Octagonal_Shape& y);

  //! Assigns to \p *this its topological closure.
  void topological_closure_assign();

  /*! \brief
    Assigns to \p *this the result of computing the
    \ref CC76_extrapolation "CC76-extrapolation" between \p *this and \p y.

    \param y
    An OS 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 Octagonal_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
    An OS 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 to 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 Octagonal_Shape& y,
                                 Iterator first, Iterator last,
                                 unsigned* tp = 0);

  /*! \brief
    Assigns to \p *this the result of computing the
    \ref BHMZ05_widening "BHMZ05-widening" between \p *this and \p y.

    \param y
    An OS 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 Octagonal_Shape& y, unsigned* tp = 0);

  //! Same as BHMZ05_widening_assign(y, tp).
  void widening_assign(const Octagonal_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
    An OS that <EM>must</EM> be contained in \p *this.

    \param cs
    The system of constraints used to improve the widened OS.

    \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 there is in \p cs a strict inequality.
  */
  void limited_BHMZ05_extrapolation_assign(const Octagonal_Shape& y,
                                           const Constraint_System& cs,
                                           unsigned* tp = 0);

  /*! \brief
    Restores from \p y the constraints of \p *this, lost by
    \ref CC76_extrapolation "CC76-extrapolation" applications.

    \param y
    An OS that <EM>must</EM> contain \p *this.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are dimension-incompatible.
  */
  void CC76_narrowing_assign(const Octagonal_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
    An OS that <EM>must</EM> be contained in \p *this.

    \param cs
    The system of constraints used to improve the widened OS.

    \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 Octagonal_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 OS 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 OS,
    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 OS \f$\cO \sseq \Rset^2\f$
    and adding a third dimension, the result will be the OS
    \f[
      \bigl\{\,
        (x, y, z)^\transpose \in \Rset^3
      \bigm|
        (x, y)^\transpose \in \cO
      \,\bigr\}.
    \f]
  */
  void add_space_dimensions_and_embed(dimension_type m);

  /*! \brief
    Adds \p m new dimensions to the OS
    and does not embed it in the new space.

    \param m
    The number of dimensions to add.

    The new dimensions will be those having the highest indexes
    in the new OS, 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 OS \f$\cO \sseq \Rset^2\f$
    and adding a third dimension, the result will be the OS
    \f[
      \bigl\{\,
        (x, y, 0)^\transpose \in \Rset^3
      \bigm|
        (x, y)^\transpose \in \cO
      \,\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::length_error
    Thrown if the concatenation would cause the vector space
    to exceed dimension <CODE>max_space_dimension()</CODE>.
  */
  void concatenate_assign(const Octagonal_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 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.
    \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 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

  PPL_OUTPUT_DECLARATIONS

  /*! \brief
    Loads from \p s an ASCII representation (as produced by
    ascii_dump(std::ostream&) const) 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
    Returns a 32-bit hash code for \p *this.

    If \p x and \p y are such that <CODE>x == y</CODE>,
    then <CODE>x.hash_code() == y.hash_code()</CODE>.
  */
  int32_t hash_code() const;

  friend bool
  operator==<T>(const Octagonal_Shape<T>& x, const Octagonal_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 Octagonal_Shape<U>& x, const Octagonal_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 Octagonal_Shape<U>& x, const Octagonal_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 Octagonal_Shape<U>& x, const Octagonal_Shape<U>& y,
   const Rounding_Dir dir, Temp& tmp0, Temp& tmp1, Temp& tmp2);

private:
  template <typename U> friend class Parma_Polyhedra_Library::Octagonal_Shape;
  template <typename Interval> friend class Parma_Polyhedra_Library::Box;

  //! The matrix that represents the octagonal shape.
  OR_Matrix<N> matrix;

  //! Dimension of the space of the octagonal shape.
  dimension_type space_dim;

  // Please, do not move the following include directive:
  // `Og_Status.idefs.hh' must be included exactly at this point.
  // And please do not remove the space separating `#' from `include':
  // this ensures that the directive will not be moved during the
  // procedure that automatically creates the library's include file
  // (see `Makefile.am' in the `src' directory).
#define PPL_IN_Octagonal_Shape_CLASS
/* Automatically generated from PPL source file ../src/Og_Status.idefs.hh line 1. */
/* Octagonal_Shape<T>::Status class declaration.
*/


#ifndef PPL_IN_Octagonal_Shape_CLASS
#error "Do not include Og_Status.idefs.hh directly; use Octagonal_Shape.defs.hh instead."
#endif

//! A conjunctive assertion about a Octagonal_Shape<T> object.
/*!
  The assertions supported are:
  - <EM>zero-dim universe</EM>: the polyhedron is the zero-dimensional
    vector space \f$\Rset^0 = \{\cdot\}\f$;
  - <EM>empty</EM>: the polyhedron is the empty set;
  - <EM>strongly closed</EM>: the Octagonal_Shape object is strongly
    closed, so that all the constraints are as tight as possible.

  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.
*/
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_strongly_closed() const;
  void reset_strongly_closed();
  void set_strongly_closed();
  //@}

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

  /*! \brief
    Writes to \p s an ASCII representation of the internal
    representation of \p *this.
  */
  void ascii_dump(std::ostream& s) const;

  /*! \brief
    Loads from \p s an ASCII representation (as produced by
    ascii_dump(std::ostream&) const) 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 STRONGLY_CLOSED = 1U << 1;
  //@}

  //! 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/Octagonal_Shape.defs.hh line 1640. */
#undef PPL_IN_Octagonal_Shape_CLASS

  //! The status flags to keep track of the internal state.
  Status status;

  //! Returns <CODE>true</CODE> if the OS is the zero-dimensional universe.
  bool marked_zero_dim_univ() const;

  //! Returns <CODE>true</CODE> if the OS 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 \c this->matrix is known to be
    strongly closed.

    The return value <CODE>false</CODE> does not necessarily
    implies that \c this->matrix is not strongly closed.
  */
  bool marked_strongly_closed() const;

  //! Turns \p *this into a zero-dimensional universe OS.
  void set_zero_dim_univ();

  //! Turns \p *this into an empty OS.
  void set_empty();

  //! Marks \p *this as strongly closed.
  void set_strongly_closed();

  //! Marks \p *this as possibly not strongly closed.
  void reset_strongly_closed();

  N& matrix_at(dimension_type i, dimension_type j);
  const N& matrix_at(dimension_type i, dimension_type j) const;

  /*! \brief
    Uses the constraint \p c to refine \p *this.

    \param c
    The constraint to be added. Non-octagonal constraints are ignored.

    \warning
    If \p c and \p *this are dimension-incompatible,
    the behavior is undefined.
  */
  void refine_no_check(const Constraint& c);

  /*! \brief
    Uses the congruence \p cg to refine \p *this.

    \param cg
    The congruence to be added.
    Nontrivial proper congruences are ignored.
    Non-octagonal equalities are ignored.

    \warning
    If \p cg and \p *this are dimension-incompatible,
    the behavior is undefined.
  */
  void refine_no_check(const Congruence& cg);

  //! Adds the constraint <CODE>matrix[i][j] <= k</CODE>.
  void add_octagonal_constraint(dimension_type i,
                                dimension_type j,
                                const N& k);

  //! Adds the constraint <CODE>matrix[i][j] <= num/den</CODE>.
  void add_octagonal_constraint(dimension_type i,
                                dimension_type j,
                                Coefficient_traits::const_reference num,
                                Coefficient_traits::const_reference den);

  /*! \brief
    Adds to the Octagonal_Shape the constraint
    \f$\mathrm{var} \relsym \frac{\mathrm{expr}}{\mathrm{denominator}}\f$.

    Note that the coefficient of \p var in \p expr is null.
  */
  void refine(Variable var,
              Relation_Symbol relsym,
              const Linear_Expression& expr,
              Coefficient_traits::const_reference denominator
              = Coefficient_one());

  //! Removes all the constraints on variable \p v_id.
  void forget_all_octagonal_constraints(dimension_type v_id);

  //! Removes all binary constraints on variable \p v_id.
  void forget_binary_octagonal_constraints(dimension_type v_id);

  //! An helper function for the computation of affine relations.
  /*!
    For each variable index \c u_id (less than or equal to \p last_id
    and different from \p v_id), deduce constraints of the form
    <CODE>v - u \<= k</CODE> and <CODE>v + u \<= k</CODE>,
    starting from \p ub_v, which is an upper bound for \c v
    computed according to \p sc_expr and \p sc_den.

    Strong-closure will be able to deduce the constraints
    <CODE>v - u \<= ub_v - lb_u</CODE> and <CODE>v + u \<= ub_v + ub_u</CODE>.
    We can be more precise if variable \c u played an active role in the
    computation of the upper bound for \c v.

    Namely, if the corresponding coefficient
    <CODE>q == sc_expr[u]/sc_den</CODE> of \c u in \p sc_expr
    is greater than zero, we can improve the bound for <CODE>v - u</CODE>.
    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>.

    Conversely, if \c q is less than zero, we can improve the bound for
    <CODE>v + u</CODE>. In particular:
      - if <CODE>q \<= -1</CODE>, then <CODE>v + u \<= ub_v + lb_u</CODE>;
      - if <CODE>-1 \< q \< 0</CODE>, then
        <CODE>v + u \<= ub_v + ((-q)*lb_u + (1+q)*ub_u)</CODE>.
  */
  void deduce_v_pm_u_bounds(dimension_type v_id,
                            dimension_type last_id,
                            const Linear_Expression& sc_expr,
                            Coefficient_traits::const_reference sc_den,
                            const N& ub_v);

  //! An helper function for the computation of affine relations.
  /*!
    For each variable index \c u_id (less than or equal to \p last_id
    and different from \p v_id), deduce constraints of the form
    <CODE>-v + u \<= k</CODE> and <CODE>-v - u \<= k</CODE>,
    starting from \p minus_lb_v, which is the negation of a lower bound
    for \c v computed according to \p sc_expr and \p sc_den.

    Strong-closure will be able to deduce the constraints
    <CODE>-v - u \<= -lb_v - lb_u</CODE> and
    <CODE>-v + u \<= -lb_v + ub_u</CODE>.
    We can be more precise if variable \c u played an active role in the
    computation of (the negation of) the lower bound for \c v.

    Namely, if the corresponding coefficient
    <CODE>q == sc_expr[u]/sc_den</CODE> of \c u in \p sc_expr
    is greater than zero, we can improve the bound for <CODE>-v + u</CODE>.
    In particular:
      - if <CODE>q \>= 1</CODE>, then <CODE>-v + u \<= -lb_v + lb_u</CODE>;
      - if <CODE>0 \< q \< 1</CODE>, then
        <CODE>-v + u \<= -lb_v + (q*lb_u + (1-q)*ub_u)</CODE>.

    Conversely, if \c q is less than zero, we can improve the bound for
    <CODE>-v - u</CODE>. In particular:
      - if <CODE>q \<= -1</CODE>, then <CODE>-v - u \<= -lb_v - ub_u</CODE>;
      - if <CODE>-1 \< q \< 0</CODE>, then
        <CODE>-v - u \<= -lb_v - ((-q)*ub_u + (1+q)*lb_u)</CODE>.
  */
  void deduce_minus_v_pm_u_bounds(dimension_type v,
                                  dimension_type last_v,
                                  const Linear_Expression& sc_expr,
                                  Coefficient_traits::const_reference sc_den,
                                  const N& minus_lb_v);

  /*! \brief
    Adds to \p limiting_octagon the octagonal differences in \p cs
    that are satisfied by \p *this.
  */
  void get_limiting_octagon(const Constraint_System& cs,
                            Octagonal_Shape& limiting_octagon) const;
  //! Compute the (zero-equivalence classes) successor relation.
  /*!
    It is assumed that the octagon is not empty and strongly closed.
  */
  void compute_successors(std::vector<dimension_type>& successor) const;

  //! Compute the leaders of zero-equivalence classes.
  /*!
    It is assumed that the OS is not empty and strongly closed.
  */
  void compute_leaders(std::vector<dimension_type>& successor,
                       std::vector<dimension_type>& no_sing_leaders,
                       bool& exist_sing_class,
                       dimension_type& sing_leader) const;

  //! Compute the leaders of zero-equivalence classes.
  /*!
    It is assumed that the OS is not empty and strongly closed.
  */
  void compute_leaders(std::vector<dimension_type>& leaders) const;

  /*! \brief
    Stores into \p non_redundant information about the matrix entries
    that are non-redundant (i.e., will occur in strongly reduced matrix).

    It is assumed that the OS is not empty and strongly closed;
    moreover, argument \p non_redundant is assumed to be empty.
  */
  void non_redundant_matrix_entries(std::vector<Bit_Row>& non_redundant) const;

  //! Removes the redundant constraints from \c this->matrix.
  void strong_reduction_assign() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \c this->matrix
    is strongly reduced.
  */
  bool is_strongly_reduced() const;

  /*! \brief
    Returns <CODE>true</CODE> if in the octagon taken two at a time
    unary constraints, there is also the constraint that represent their sum.
  */
  bool is_strong_coherent() const;

  bool tight_coherence_would_make_empty() const;

  //! Assigns to \c this->matrix its strong closure.
  /*!
    Strong closure is a necessary condition for the precision and/or
    the correctness of many methods. It explicitly records into \c matrix
    those constraints that are implicitly obtainable by the other ones,
    therefore obtaining a canonical representation for the OS.
  */
  void strong_closure_assign() const;

  //! Applies the strong-coherence step to \c this->matrix.
  void strong_coherence_assign();

  /*! \brief
    Incrementally computes strong closure, assuming that only
    constraints affecting variable \p var need to be considered.

    \note
    It is assumed that \c *this, which was strongly closed, has only been
    modified by adding constraints affecting variable \p var. If this
    assumption is not satisfied, i.e., if a non-redundant constraint not
    affecting variable \p var has been added, the behavior is undefined.
    Worst-case complexity is \f$O(n^2)\f$.
  */
  void incremental_strong_closure_assign(Variable var) 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;

    \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 and
    \p included are left untouched.
  */
  bool max_min(const Linear_Expression& expr,
               bool maximize,
               Coefficient& ext_n, Coefficient& ext_d, bool& included) 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 g
    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 g are left untouched.
  */
  bool max_min(const Linear_Expression& expr,
               bool maximize,
               Coefficient& ext_n, Coefficient& ext_d, bool& included,
               Generator& g) const;

  bool BHZ09_upper_bound_assign_if_exact(const Octagonal_Shape& y);

  friend std::ostream&
  Parma_Polyhedra_Library::IO_Operators
  ::operator<<<>(std::ostream& s, const Octagonal_Shape<T>& c);

  //! \name Exception Throwers
  //@{
  void throw_dimension_incompatible(const char* method,
                                    const Octagonal_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 Congruence& cg) 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;

  void throw_constraint_incompatible(const char* method) const;

  void throw_expression_too_complex(const char* method,
                                    const Linear_Expression& e) const;

  void throw_generic(const char* method, const char* reason) const;
  //@} // Exception Throwers

  static T default_stop_points[];
};

namespace std {

//! Specializes <CODE>std::swap</CODE>.
/*! \relates Parma_Polyhedra_Library::Octagonal_Shape */
template <typename T>
void swap(Parma_Polyhedra_Library::Octagonal_Shape<T>& x,
          Parma_Polyhedra_Library::Octagonal_Shape<T>& y);

} // namespace std

/* Automatically generated from PPL source file ../src/Og_Status.inlines.hh line 1. */
/* Octagonal_Shape<T>::Status class implementation: inline functions.
*/


namespace Parma_Polyhedra_Library {

template <typename T>
inline
Octagonal_Shape<T>::Status::Status(flags_t mask)
  : flags(mask) {
}

template <typename T>
inline
Octagonal_Shape<T>::Status::Status()
  : flags(ZERO_DIM_UNIV) {
}

template <typename T>
inline bool
Octagonal_Shape<T>::Status::test_all(flags_t mask) const {
  return (flags & mask) == mask;
}

template <typename T>
inline bool
Octagonal_Shape<T>::Status::test_any(flags_t mask) const {
  return flags & mask;
}

template <typename T>
inline void
Octagonal_Shape<T>::Status::set(flags_t mask) {
  flags |= mask;
}

template <typename T>
inline void
Octagonal_Shape<T>::Status::reset(flags_t mask) {
  flags &= ~mask;
}

template <typename T>
inline bool
Octagonal_Shape<T>::Status::test_zero_dim_univ() const {
  return flags == ZERO_DIM_UNIV;
}

template <typename T>
inline void
Octagonal_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
Octagonal_Shape<T>::Status::set_zero_dim_univ() {
  // Zero-dim universe is incompatible with anything else.
  flags = ZERO_DIM_UNIV;
}

template <typename T>
inline bool
Octagonal_Shape<T>::Status::test_empty() const {
  return test_any(EMPTY);
}

template <typename T>
inline void
Octagonal_Shape<T>::Status::reset_empty() {
  reset(EMPTY);
}

template <typename T>
inline void
Octagonal_Shape<T>::Status::set_empty() {
  flags = EMPTY;
}

template <typename T>
inline bool
Octagonal_Shape<T>::Status::test_strongly_closed() const {
  return test_any(STRONGLY_CLOSED);
}

template <typename T>
inline void
Octagonal_Shape<T>::Status::reset_strongly_closed() {
  reset(STRONGLY_CLOSED);
}

template <typename T>
inline void
Octagonal_Shape<T>::Status::set_strongly_closed() {
  set(STRONGLY_CLOSED);
}

template <typename T>
inline bool
Octagonal_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;
    }
  }

  // Any other case is OK.
  return true;
}


namespace Implementation {

namespace Octagonal_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 strong_closed = "SC";
const char yes = '+';
const char no = '-';
const char sep = ' ';

/*! \relates Parma_Polyhedra_Library::Octagonal_Shape<T>::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 Octagonal_Shapes

} // namespace Implementation

template <typename T>
inline void
Octagonal_Shape<T>::Status::ascii_dump(std::ostream& s) const {
  using namespace Implementation::Octagonal_Shapes;
  s << (test_zero_dim_univ() ? yes : no) << zero_dim_univ
    << sep
    << (test_empty() ? yes : no) << empty
    << sep
    << sep
    << (test_strongly_closed() ? yes : no) << strong_closed
    << sep;
}

template <typename T>
inline bool
Octagonal_Shape<T>::Status::ascii_load(std::istream& s) {
  using namespace Implementation::Octagonal_Shapes;
  PPL_UNINITIALIZED(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, strong_closed, positive))
    return false;
  if (positive)
    set_strongly_closed();
  else
    reset_strongly_closed();

  // Check invariants.
  assert(OK());
  return true;
}

} // namespace Parma_Polyhedra_Library

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


/* Automatically generated from PPL source file ../src/Octagonal_Shape.inlines.hh line 34. */
#include <cassert>
#include <algorithm>

namespace Parma_Polyhedra_Library {

// FIXME: find the appropriate place for this.
/*! \relates Octagonal_Shape */
inline dimension_type
coherent_index(const dimension_type i) {
  return (i % 2 != 0) ? i-1 : i+1;
}

template <typename T>
inline dimension_type
Octagonal_Shape<T>::max_space_dimension() {
  return OR_Matrix<N>::max_num_rows()/2;
}

template <typename T>
inline bool
Octagonal_Shape<T>::marked_zero_dim_univ() const {
  return status.test_zero_dim_univ();
}

template <typename T>
inline bool
Octagonal_Shape<T>::marked_strongly_closed() const {
  return status.test_strongly_closed();
}

template <typename T>
inline bool
Octagonal_Shape<T>::marked_empty() const {
  return status.test_empty();
}

template <typename T>
inline void
Octagonal_Shape<T>::set_zero_dim_univ() {
  status.set_zero_dim_univ();
}

template <typename T>
inline void
Octagonal_Shape<T>::set_empty() {
  status.set_empty();
}

template <typename T>
inline void
Octagonal_Shape<T>::set_strongly_closed() {
  status.set_strongly_closed();
}

template <typename T>
inline void
Octagonal_Shape<T>::reset_strongly_closed() {
  status.reset_strongly_closed();
}

template <typename T>
inline
Octagonal_Shape<T>::Octagonal_Shape(const dimension_type num_dimensions,
				    const Degenerate_Element kind)
  : matrix(num_dimensions), space_dim(num_dimensions), status() {
  if (kind == EMPTY)
    set_empty();
  else if (num_dimensions > 0)
    // A (non zero-dim) universe octagon is strongly closed.
    set_strongly_closed();
  assert(OK());
}

template <typename T>
inline
Octagonal_Shape<T>::Octagonal_Shape(const Octagonal_Shape& y, Complexity_Class)
  : matrix(y.matrix), space_dim(y.space_dim), status(y.status) {
}

template <typename T>
template <typename U>
inline
Octagonal_Shape<T>::Octagonal_Shape(const Octagonal_Shape<U>& y,
                                    Complexity_Class)
  // For maximum precision, enforce shortest-path closure
  // before copying the DB matrix.
  : matrix((y.strong_closure_assign(), y.matrix)),
    space_dim(y.space_dim),
    status() {
  // TODO: handle flags properly, possibly taking special cases into account.
  if (y.marked_empty())
    set_empty();
  else if (y.marked_zero_dim_univ())
    set_zero_dim_univ();
}

template <typename T>
inline
Octagonal_Shape<T>::Octagonal_Shape(const Constraint_System& cs)
  : matrix(cs.space_dimension()),
    space_dim(cs.space_dimension()),
    status() {
  if (cs.space_dimension() > 0)
    // A (non zero-dim) universe octagon is strongly closed.
    set_strongly_closed();
  add_constraints(cs);
}

template <typename T>
inline
Octagonal_Shape<T>::Octagonal_Shape(const Congruence_System& cgs)
  : matrix(cgs.space_dimension()),
    space_dim(cgs.space_dimension()),
    status() {
  if (cgs.space_dimension() > 0)
    // A (non zero-dim) universe octagon is strongly closed.
    set_strongly_closed();
  add_congruences(cgs);
}

template <typename T>
template <typename Interval>
inline
Octagonal_Shape<T>::Octagonal_Shape(const Box<Interval>& box,
                                    Complexity_Class)
  : matrix(box.space_dimension()),
    space_dim(box.space_dimension()),
    status() {
  // Check for emptyness for maximum precision.
  if (box.is_empty())
    set_empty();
  else if (box.space_dimension() > 0) {
    // A (non zero-dim) universe OS is strongly closed.
    set_strongly_closed();
    refine_with_constraints(box.constraints());
  }
}

template <typename T>
inline
Octagonal_Shape<T>::Octagonal_Shape(const Grid& grid,
                                    Complexity_Class)
  : matrix(grid.space_dimension()),
    space_dim(grid.space_dimension()),
    status() {
  if (grid.space_dimension() > 0)
    // A (non zero-dim) universe OS is strongly closed.
    set_strongly_closed();
  // Taking minimized congruences ensures maximum precision.
  refine_with_congruences(grid.minimized_congruences());
}

template <typename T>
template <typename U>
inline
Octagonal_Shape<T>::Octagonal_Shape(const BD_Shape<U>& bd,
                                    Complexity_Class)
  : matrix(bd.space_dimension()),
    space_dim(bd.space_dimension()),
    status() {
  // Check for emptyness for maximum precision.
  if (bd.is_empty())
    set_empty();
  else if (bd.space_dimension() > 0) {
    // A (non zero-dim) universe OS is strongly closed.
    set_strongly_closed();
    refine_with_constraints(bd.constraints());
  }
}

template <typename T>
inline Congruence_System
Octagonal_Shape<T>::congruences() const {
  return minimized_congruences();
}

template <typename T>
inline Octagonal_Shape<T>&
Octagonal_Shape<T>::operator=(const Octagonal_Shape& y) {
  matrix = y.matrix;
  space_dim = y.space_dim;
  status = y.status;
  return *this;
}

template <typename T>
inline
Octagonal_Shape<T>::~Octagonal_Shape() {
}

template <typename T>
inline void
Octagonal_Shape<T>::swap(Octagonal_Shape& y) {
  std::swap(matrix, y.matrix);
  std::swap(space_dim, y.space_dim);
  std::swap(status, y.status);
}

template <typename T>
inline dimension_type
Octagonal_Shape<T>::space_dimension() const {
  return space_dim;
}

template <typename T>
inline bool
Octagonal_Shape<T>::is_discrete() const {
  return affine_dimension() == 0;
}

template <typename T>
inline bool
Octagonal_Shape<T>::is_empty() const {
  strong_closure_assign();
  return marked_empty();
}

template <typename T>
inline bool
Octagonal_Shape<T>::bounds_from_above(const Linear_Expression& expr) const {
  return bounds(expr, true);
}

template <typename T>
inline bool
Octagonal_Shape<T>::bounds_from_below(const Linear_Expression& expr) const {
  return bounds(expr, false);
}

template <typename T>
inline bool
Octagonal_Shape<T>::maximize(const Linear_Expression& expr,
			     Coefficient& sup_n, Coefficient& sup_d,
			     bool& maximum) const {
  return max_min(expr, true, sup_n, sup_d, maximum);
}

template <typename T>
inline bool
Octagonal_Shape<T>::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);
}

template <typename T>
inline bool
Octagonal_Shape<T>::minimize(const Linear_Expression& expr,
			     Coefficient& inf_n, Coefficient& inf_d,
			     bool& minimum) const {
  return max_min(expr, false, inf_n, inf_d, minimum);
}

template <typename T>
inline bool
Octagonal_Shape<T>::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);
}

template <typename T>
inline bool
Octagonal_Shape<T>::is_topologically_closed() const {
  return true;
}

template <typename T>
inline void
Octagonal_Shape<T>::topological_closure_assign() {
  // Nothing to be done.
  return;
}

/*! \relates Octagonal_Shape */
template <typename T>
inline bool
operator==(const Octagonal_Shape<T>& x, const Octagonal_Shape<T>& y) {
  if (x.space_dim != y.space_dim)
    // Dimension-incompatible OSs are different.
    return false;

  // Zero-dim OSs 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();
  }

  x.strong_closure_assign();
  y.strong_closure_assign();
  // If one of two octagons is empty, then they are equal if and only if
  // the other octagon is empty too.
  if (x.marked_empty())
    return y.marked_empty();
  if (y.marked_empty())
    return false;
  // Strong closure is a canonical form.
  return x.matrix == y.matrix;
}

/*! \relates Octagonal_Shape */
template <typename T>
inline bool
operator!=(const Octagonal_Shape<T>& x, const Octagonal_Shape<T>& y) {
  return !(x == y);
}

template <typename T>
inline const typename Octagonal_Shape<T>::coefficient_type&
Octagonal_Shape<T>::matrix_at(const dimension_type i,
			      const dimension_type j) const {
  assert(i < matrix.num_rows() && j < matrix.num_rows());
  return (j < matrix.row_size(i))
    ? matrix[i][j]
    : matrix[coherent_index(j)][coherent_index(i)];
}

template <typename T>
inline typename Octagonal_Shape<T>::coefficient_type&
Octagonal_Shape<T>::matrix_at(const dimension_type i,
			      const dimension_type j) {
  assert(i < matrix.num_rows() && j < matrix.num_rows());
  return (j < matrix.row_size(i))
    ? matrix[i][j]
    : matrix[coherent_index(j)][coherent_index(i)];
}

template <typename T>
inline Constraint_System
Octagonal_Shape<T>::minimized_constraints() const {
  strong_reduction_assign();
  return constraints();
}

template <typename T>
inline void
Octagonal_Shape<T>::add_octagonal_constraint(const dimension_type i,
					     const dimension_type j,
					     const N& k) {
  // Private method: the caller has to ensure the following.
#ifndef NDEBUG
  assert(i < 2*space_dim && j < 2*space_dim && i != j);
  typename OR_Matrix<N>::row_iterator m_i = matrix.row_begin() + i;
  assert(j < m_i.row_size());
#endif
  N& r_i_j = matrix[i][j];
  if (r_i_j > k) {
    r_i_j = k;
    if (marked_strongly_closed())
      reset_strongly_closed();
  }
}

template <typename T>
inline void
Octagonal_Shape<T>
::add_octagonal_constraint(const dimension_type i,
			   const dimension_type j,
			   Coefficient_traits::const_reference num,
			   Coefficient_traits::const_reference den) {
#ifndef NDEBUG
  // Private method: the caller has to ensure the following.
  assert(i < 2*space_dim && j < 2*space_dim && i != j);
  typename OR_Matrix<N>::row_iterator m_i = matrix.row_begin() + i;
  assert(j < m_i.row_size());
  assert(den != 0);
#endif
  PPL_DIRTY_TEMP(N, k);
  div_round_up(k, num, den);
  add_octagonal_constraint(i, j, k);
}

template <typename T>
inline void
Octagonal_Shape<T>::add_constraints(const Constraint_System& cs) {
  for (Constraint_System::const_iterator i = cs.begin(),
         i_end = cs.end(); i != i_end; ++i)
    add_constraint(*i);
}

template <typename T>
inline void
Octagonal_Shape<T>::add_recycled_constraints(Constraint_System& cs) {
  add_constraints(cs);
}

template <typename T>
inline void
Octagonal_Shape<T>::add_recycled_congruences(Congruence_System& cgs) {
  add_congruences(cgs);
}

template <typename T>
inline void
Octagonal_Shape<T>::add_congruences(const Congruence_System& cgs) {
  for (Congruence_System::const_iterator i = cgs.begin(),
         cgs_end = cgs.end(); i != cgs_end; ++i)
    add_congruence(*i);
}

template <typename T>
inline void
Octagonal_Shape<T>::refine_with_constraint(const Constraint& c) {
  // Dimension-compatibility check.
  if (c.space_dimension() > space_dimension())
    throw_dimension_incompatible("refine_with_constraint(c)", c);

  if (!marked_empty())
    refine_no_check(c);
}

template <typename T>
inline void
Octagonal_Shape<T>::refine_with_constraints(const Constraint_System& cs) {
  // Dimension-compatibility check.
  if (cs.space_dimension() > space_dimension())
    throw_generic("refine_with_constraints(cs)",
                  "cs and *this are space-dimension incompatible");

  for (Constraint_System::const_iterator i = cs.begin(),
	 cs_end = cs.end(); !marked_empty() && i != cs_end; ++i)
    refine_no_check(*i);
}

template <typename T>
inline void
Octagonal_Shape<T>::refine_with_congruence(const Congruence& cg) {
  const dimension_type cg_space_dim = cg.space_dimension();
  // Dimension-compatibility check.
  if (cg_space_dim > space_dimension())
    throw_dimension_incompatible("refine_with_congruence(cg)", cg);

  if (!marked_empty())
    refine_no_check(cg);
}

template <typename T>
void
Octagonal_Shape<T>::refine_with_congruences(const Congruence_System& cgs) {
  // Dimension-compatibility check.
  if (cgs.space_dimension() > space_dimension())
    throw_generic("refine_with_congruences(cgs)",
                  "cgs and *this are space-dimension incompatible");

  for (Congruence_System::const_iterator i = cgs.begin(),
	 cgs_end = cgs.end(); !marked_empty() && i != cgs_end; ++i)
    refine_no_check(*i);
}

template <typename T>
inline void
Octagonal_Shape<T>::refine_no_check(const Congruence& cg) {
  assert(!marked_empty());
  assert(cg.space_dimension() <= space_dimension());

  if (cg.is_proper_congruence()) {
    if (cg.is_inconsistent())
      set_empty();
    // Other proper congruences are just ignored.
    return;
  }

  assert(cg.is_equality());
  Constraint c(cg);
  refine_no_check(c);
}

template <typename T>
inline bool
Octagonal_Shape<T>::can_recycle_constraint_systems() {
  return false;
}

template <typename T>
inline bool
Octagonal_Shape<T>::can_recycle_congruence_systems() {
  return false;
}

template <typename T>
inline void
Octagonal_Shape<T>
::remove_higher_space_dimensions(const dimension_type new_dimension) {
  // Dimension-compatibility check.
  if (new_dimension > space_dim)
    throw_dimension_incompatible("remove_higher_space_dimension(nd)",
				 new_dimension);
  // The removal of no dimensions from any octagon is a no-op.
  // Note that this case also captures the only legal removal of
  // dimensions from an octagon in a 0-dim space.
  if (new_dimension == space_dim) {
    assert(OK());
    return;
  }

  strong_closure_assign();
  matrix.shrink(new_dimension);
  // When we remove all dimensions from a non-empty octagon,
  // we obtain the zero-dimensional universe octagon.
  if (new_dimension == 0 && !marked_empty())
    set_zero_dim_univ();
  space_dim = new_dimension;
  assert(OK());
}

template <typename T>
inline void
Octagonal_Shape<T>::widening_assign(const Octagonal_Shape& y, unsigned* tp) {
  BHMZ05_widening_assign(y, tp);
}

template <typename T>
inline void
Octagonal_Shape<T>::CC76_extrapolation_assign(const Octagonal_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
Octagonal_Shape<T>::time_elapse_assign(const Octagonal_Shape& y) {
  // Dimension-compatibility check.
  if (space_dimension() != y.space_dimension())
    throw_dimension_incompatible("time_elapse_assign(y)", y);
  // See the polyhedra documentation.
  C_Polyhedron px(constraints());
  C_Polyhedron py(y.constraints());
  px.time_elapse_assign(py);
  Octagonal_Shape<T> x(px);
  swap(x);
  assert(OK());
}

template <typename T>
inline bool
Octagonal_Shape<T>::strictly_contains(const Octagonal_Shape& y) const {
  const Octagonal_Shape<T>& x = *this;
  return x.contains(y) && !y.contains(x);
}

template <typename T>
inline bool
Octagonal_Shape<T>::upper_bound_assign_if_exact(const Octagonal_Shape& y) {
  return BHZ09_upper_bound_assign_if_exact(y);
}

/*! \relates Octagonal_Shape */
template <typename Temp, typename To, typename T>
inline bool
rectilinear_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			    const Octagonal_Shape<T>& x,
			    const Octagonal_Shape<T>& y,
			    const Rounding_Dir dir,
			    Temp& tmp0,
			    Temp& tmp1,
			    Temp& tmp2) {
  // Dimension-compatibility check.
  if (x.space_dim != y.space_dim)
    return false;

  // Zero-dim OSs 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
      assign_r(r, PLUS_INFINITY, ROUND_NOT_NEEDED);
    return true;
  }

  // The distance computation requires strong closure.
  x.strong_closure_assign();
  y.strong_closure_assign();

  // If one of two OSs is empty, then they are equal if and only if
  // the other OS 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
      assign_r(r, PLUS_INFINITY, ROUND_NOT_NEEDED);
   return true;
  }

  return rectilinear_distance_assign(r, x.matrix, y.matrix, dir,
				     tmp0, tmp1, tmp2);
}

/*! \relates Octagonal_Shape */
template <typename Temp, typename To, typename T>
inline bool
rectilinear_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			    const Octagonal_Shape<T>& x,
			    const Octagonal_Shape<T>& y,
			    const Rounding_Dir dir) {
  typedef Checked_Number<Temp, Extended_Number_Policy> Checked_Temp;
  PPL_DIRTY_TEMP(Checked_Temp, tmp0);
  PPL_DIRTY_TEMP(Checked_Temp, tmp1);
  PPL_DIRTY_TEMP(Checked_Temp, tmp2);
  return rectilinear_distance_assign(r, x, y, dir, tmp0, tmp1, tmp2);
}

/*! \relates Octagonal_Shape */
template <typename To, typename T>
inline bool
rectilinear_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			    const Octagonal_Shape<T>& x,
			    const Octagonal_Shape<T>& y,
			    const Rounding_Dir dir) {
  return rectilinear_distance_assign<To, To, T>(r, x, y, dir);
}

/*! \relates Octagonal_Shape */
template <typename Temp, typename To, typename T>
inline bool
euclidean_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			  const Octagonal_Shape<T>& x,
			  const Octagonal_Shape<T>& y,
			  const Rounding_Dir dir,
			  Temp& tmp0,
			  Temp& tmp1,
			  Temp& tmp2) {
  // Dimension-compatibility check.
  if (x.space_dim != y.space_dim)
    return false;

  // Zero-dim OSs 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
      assign_r(r, PLUS_INFINITY, ROUND_NOT_NEEDED);
    return true;
  }

  // The distance computation requires strong closure.
  x.strong_closure_assign();
  y.strong_closure_assign();

  // If one of two OSs is empty, then they are equal if and only if
  // the other OS 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
      assign_r(r, PLUS_INFINITY, ROUND_NOT_NEEDED);
   return true;
  }

  return euclidean_distance_assign(r, x.matrix, y.matrix, dir,
				   tmp0, tmp1, tmp2);
}

/*! \relates Octagonal_Shape */
template <typename Temp, typename To, typename T>
inline bool
euclidean_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			  const Octagonal_Shape<T>& x,
			  const Octagonal_Shape<T>& y,
			  const Rounding_Dir dir) {
  typedef Checked_Number<Temp, Extended_Number_Policy> Checked_Temp;
  PPL_DIRTY_TEMP(Checked_Temp, tmp0);
  PPL_DIRTY_TEMP(Checked_Temp, tmp1);
  PPL_DIRTY_TEMP(Checked_Temp, tmp2);
  return euclidean_distance_assign(r, x, y, dir, tmp0, tmp1, tmp2);
}

/*! \relates Octagonal_Shape */
template <typename To, typename T>
inline bool
euclidean_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			  const Octagonal_Shape<T>& x,
			  const Octagonal_Shape<T>& y,
			  const Rounding_Dir dir) {
  return euclidean_distance_assign<To, To, T>(r, x, y, dir);
}

/*! \relates Octagonal_Shape */
template <typename Temp, typename To, typename T>
inline bool
l_infinity_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			   const Octagonal_Shape<T>& x,
			   const Octagonal_Shape<T>& y,
			   const Rounding_Dir dir,
			   Temp& tmp0,
			   Temp& tmp1,
			   Temp& tmp2) {
  // Dimension-compatibility check.
  if (x.space_dim != y.space_dim)
    return false;

  // Zero-dim OSs 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
      assign_r(r, PLUS_INFINITY, ROUND_NOT_NEEDED);
    return true;
  }

  // The distance computation requires strong closure.
  x.strong_closure_assign();
  y.strong_closure_assign();

  // If one of two OSs is empty, then they are equal if and only if
  // the other OS 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
      assign_r(r, PLUS_INFINITY, ROUND_NOT_NEEDED);
   return true;
  }

  return l_infinity_distance_assign(r, x.matrix, y.matrix, dir,
				    tmp0, tmp1, tmp2);
}

/*! \relates Octagonal_Shape */
template <typename Temp, typename To, typename T>
inline bool
l_infinity_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			   const Octagonal_Shape<T>& x,
			   const Octagonal_Shape<T>& y,
			   const Rounding_Dir dir) {
  typedef Checked_Number<Temp, Extended_Number_Policy> Checked_Temp;
  PPL_DIRTY_TEMP(Checked_Temp, tmp0);
  PPL_DIRTY_TEMP(Checked_Temp, tmp1);
  PPL_DIRTY_TEMP(Checked_Temp, tmp2);
  return l_infinity_distance_assign(r, x, y, dir, tmp0, tmp1, tmp2);
}

/*! \relates Octagonal_Shape */
template <typename To, typename T>
inline bool
l_infinity_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			   const Octagonal_Shape<T>& x,
			   const Octagonal_Shape<T>& y,
			   const Rounding_Dir dir) {
  return l_infinity_distance_assign<To, To, T>(r, x, y, dir);
}

template <typename T>
inline memory_size_type
Octagonal_Shape<T>::total_memory_in_bytes() const {
  return sizeof(*this) + external_memory_in_bytes();
}

template <typename T>
inline int32_t
Octagonal_Shape<T>::hash_code() const {
  return space_dimension() & 0x7fffffff;
}

} // namespace Parma_Polyhedra_Library

namespace std {

/*! \relates Parma_Polyhedra_Library::Octagonal_Shape */
template <typename T>
inline void
swap(Parma_Polyhedra_Library::Octagonal_Shape<T>& x,
     Parma_Polyhedra_Library::Octagonal_Shape<T>& y) {
  x.swap(y);
}

} // namespace std

/* Automatically generated from PPL source file ../src/Octagonal_Shape.templates.hh line 1. */
/* Octagonal_Shape class implementation: non-inline template functions.
*/


/* Automatically generated from PPL source file ../src/Octagonal_Shape.templates.hh line 30. */
#include <cassert>
#include <vector>
#include <deque>
#include <string>
#include <iostream>
#include <sstream>
#include <stdexcept>
#include <algorithm>

namespace Parma_Polyhedra_Library {

template <typename T>
Octagonal_Shape<T>::Octagonal_Shape(const Polyhedron& ph,
                                    const Complexity_Class complexity)
  : matrix(0), space_dim(0), status() {
  const dimension_type num_dimensions = ph.space_dimension();

  if (ph.marked_empty()) {
    *this = Octagonal_Shape(num_dimensions, EMPTY);
    return;
  }

  if (num_dimensions == 0) {
    *this = Octagonal_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 = Octagonal_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 = Octagonal_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 = Octagonal_Shape(num_dimensions, EMPTY);
      return;
    }

  // If `complexity' allows it, use simplex to derive the exact (modulo
  // the fact that our OSs are topologically closed) variable bounds.
  if (complexity == SIMPLEX_COMPLEXITY) {
    MIP_Problem lp(num_dimensions);
    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(),
             ph_cs_end = ph_cs.end(); i != ph_cs_end; ++i) {
        const Constraint& c = *i;
        if (c.is_strict_inequality())
          lp.add_constraint(Linear_Expression(c) >= 0);
        else
          lp.add_constraint(c);
      }

    // Check for unsatisfiability.
    if (!lp.is_satisfiable()) {
      *this = Octagonal_Shape<T>(num_dimensions, EMPTY);
      return;
    }

    // Start with a universe OS that will be refined by the simplex.
    *this = Octagonal_Shape<T>(num_dimensions, UNIVERSE);
    // Get all the upper bounds.
    Generator g(point());
    PPL_DIRTY_TEMP_COEFFICIENT(num);
    PPL_DIRTY_TEMP_COEFFICIENT(den);
    for (dimension_type i = 0; i < num_dimensions; ++i) {
      Variable x(i);
      // Evaluate optimal upper bound for `x <= ub'.
      lp.set_objective_function(x);
      if (lp.solve() == OPTIMIZED_MIP_PROBLEM) {
        g = lp.optimizing_point();
        lp.evaluate_objective_function(g, num, den);
        num *= 2;
        div_round_up(matrix[2*i+1][2*i], num, den);
      }
      // Evaluate optimal upper bounds for `x + y <= ub'.
      for (dimension_type j = 0; j < i; ++j) {
        Variable y(j);
        lp.set_objective_function(x + y);
        if (lp.solve() == OPTIMIZED_MIP_PROBLEM) {
          g = lp.optimizing_point();
          lp.evaluate_objective_function(g, num, den);
          div_round_up(matrix[2*i+1][2*j], num, den);
        }
      }
      // Evaluate optimal upper bound for `x - y <= ub'.
      for (dimension_type j = 0; j < num_dimensions; ++j) {
        if (i == j)
          continue;
        Variable y(j);
        lp.set_objective_function(x - y);
        if (lp.solve() == OPTIMIZED_MIP_PROBLEM) {
          g = lp.optimizing_point();
          lp.evaluate_objective_function(g, num, den);
          div_round_up((i < j ? matrix[2*j][2*i] : matrix[2*i+1][2*j+1]),
                       num, den);
        }
      }
      // Evaluate optimal upper bound for `y - x <= ub'.
      for (dimension_type j = 0; j < num_dimensions; ++j) {
        if (i == j)
          continue;
        Variable y(j);
        lp.set_objective_function(x - y);
        if (lp.solve() == OPTIMIZED_MIP_PROBLEM) {
          g = lp.optimizing_point();
          lp.evaluate_objective_function(g, num, den);
          div_round_up((i < j ? matrix[2*j][2*i] : matrix[2*i+1][2*j+1]),
                       num, den);
        }
      }
      // Evaluate optimal upper bound for `-x - y <= ub'.
      for (dimension_type j = 0; j < i; ++j) {
        Variable y(j);
        lp.set_objective_function(-x - y);
        if (lp.solve() == OPTIMIZED_MIP_PROBLEM) {
          g = lp.optimizing_point();
          lp.evaluate_objective_function(g, num, den);
           div_round_up(matrix[2*i][2*j+1], num, den);
        }
      }
      // Evaluate optimal upper bound for `-x <= ub'.
      lp.set_objective_function(-x);
      if (lp.solve() == OPTIMIZED_MIP_PROBLEM) {
        g = lp.optimizing_point();
        lp.evaluate_objective_function(g, num, den);
        num *= 2;
        div_round_up(matrix[2*i][2*i+1], num, den);
      }
    }
    set_strongly_closed();
    assert(OK());
    return;
  }

  // Extract easy-to-find bounds from constraints.
  assert(complexity == POLYNOMIAL_COMPLEXITY);
  *this = Octagonal_Shape(num_dimensions, UNIVERSE);
  refine_with_constraints(ph.constraints());
}

template <typename T>
Octagonal_Shape<T>::Octagonal_Shape(const Generator_System& gs)
  : matrix(gs.space_dimension()),
    space_dim(gs.space_dimension()),
    status() {
  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();
    return;
  }

  typedef typename OR_Matrix<N>::row_reference_type Row_Reference;
  typename OR_Matrix<N>::row_iterator mat_begin = matrix.row_begin();

  PPL_DIRTY_TEMP(N, tmp);
  bool mat_initialized = false;
  bool point_seen = false;
  // Going through all the points and closure points.
  for (Generator_System::const_iterator k = gs_begin; k != gs_end; ++k) {
    const Generator& g = *k;
    switch (g.type()) {
    case Generator::POINT:
      point_seen = true;
      // Intentionally fall through.
    case Generator::CLOSURE_POINT:
      if (!mat_initialized) {
        // When handling the first (closure) point, we initialize the matrix.
        mat_initialized = true;
        const Coefficient& d = g.divisor();
        for (dimension_type i = 0; i < space_dim; ++i) {
          const Coefficient& g_i = g.coefficient(Variable(i));
          const dimension_type di = 2*i;
          Row_Reference x_i = *(mat_begin+di);
          Row_Reference x_ii = *(mat_begin+di+1);
          for (dimension_type j = 0; j < i; ++j) {
            const Coefficient& g_j = g.coefficient(Variable(j));
            const dimension_type dj = 2*j;
            // Set for any point the hyperplanes passing in the point
            // and having the octagonal gradient.
            // Let be P = [P_1, P_2, ..., P_n] point.
            // Hyperplanes: X_i - X_j = P_i - P_j.
            div_round_up(x_i[dj], g_j - g_i, d);
            div_round_up(x_ii[dj+1], g_i - g_j, d);
            // Hyperplanes: X_i + X_j = P_i + P_j.
            div_round_up(x_i[dj+1], -g_j - g_i, d);
            div_round_up(x_ii[dj], g_i + g_j, d);
          }
          // Hyperplanes: X_i = P_i.
          div_round_up(x_i[di+1], -g_i - g_i, d);
          div_round_up(x_ii[di], g_i + g_i, d);
        }
      }
      else {
        // This is not the first point: the matrix already contains
        // valid values and we must compute maxima.
        const Coefficient& d = g.divisor();
        for (dimension_type i = 0; i < space_dim; ++i) {
          const Coefficient& g_i = g.coefficient(Variable(i));
          const dimension_type di = 2*i;
          Row_Reference x_i = *(mat_begin+di);
          Row_Reference x_ii = *(mat_begin+di+1);
          for (dimension_type j = 0; j < i; ++j) {
            const Coefficient& g_j = g.coefficient(Variable(j));
            const dimension_type dj = 2*j;
            // Set for any point the straight lines passing in the point
            // and having the octagonal gradient; compute maxima values.
            // Let be P = [P_1, P_2, ..., P_n] point.
            // Hyperplane: X_i - X_j = max (P_i - P_j, const).
            div_round_up(tmp, g_j - g_i, d);
            max_assign(x_i[dj], tmp);
            div_round_up(tmp, g_i - g_j, d);
            max_assign(x_ii[dj+1], tmp);
            // Hyperplane: X_i + X_j = max (P_i + P_j, const).
            div_round_up(tmp, -g_j - g_i, d);
            max_assign(x_i[dj+1], tmp);
            div_round_up(tmp, g_i + g_j, d);
            max_assign(x_ii[dj], tmp);
          }
          // Hyperplane: X_i = max (P_i, const).
          div_round_up(tmp, -g_i - g_i, d);
          max_assign(x_i[di+1], tmp);
          div_round_up(tmp, g_i + g_i, d);
          max_assign(x_ii[di], tmp);
        }
      }
      break;
    default:
      // Lines and rays temporarily ignored.
      break;
    }
  }

  if (!point_seen)
    // The generator system is not empty, but contains no points.
    throw_generic("Octagonal_Shape(gs)",
                  "the non-empty generator system gs contains no points.");

  // Going through all the lines and rays.
  for (Generator_System::const_iterator k = gs_begin; k != gs_end; ++k) {
    const Generator& g = *k;
    switch (g.type()) {
    case Generator::LINE:
        for (dimension_type i = 0; i < space_dim; ++i) {
          const Coefficient& g_i = g.coefficient(Variable(i));
          const dimension_type di = 2*i;
          Row_Reference x_i = *(mat_begin+di);
          Row_Reference x_ii = *(mat_begin+di+1);
          for (dimension_type j = 0; j < i; ++j) {
            const Coefficient& g_j = g.coefficient(Variable(j));
            const dimension_type dj = 2*j;
            // Set for any line the right limit.
            if (g_i != g_j) {
              // Hyperplane: X_i - X_j <=/>= +Inf.
              assign_r(x_i[dj], PLUS_INFINITY, ROUND_NOT_NEEDED);
              assign_r(x_ii[dj+1], PLUS_INFINITY, ROUND_NOT_NEEDED);
            }
            if (g_i != -g_j) {
              // Hyperplane: X_i + X_j <=/>= +Inf.
              assign_r(x_i[dj+1], PLUS_INFINITY, ROUND_NOT_NEEDED);
              assign_r(x_ii[dj], PLUS_INFINITY, ROUND_NOT_NEEDED);
            }
          }
          if (g_i != 0) {
            // Hyperplane: X_i <=/>= +Inf.
            assign_r(x_i[di+1], PLUS_INFINITY, ROUND_NOT_NEEDED);
            assign_r(x_ii[di], PLUS_INFINITY, ROUND_NOT_NEEDED);
          }
        }
      break;
    case Generator::RAY:
        for (dimension_type i = 0; i < space_dim; ++i) {
          const Coefficient& g_i = g.coefficient(Variable(i));
          const dimension_type di = 2*i;
          Row_Reference x_i = *(mat_begin+di);
          Row_Reference x_ii = *(mat_begin+di+1);
          for (dimension_type j = 0; j < i; ++j) {
            const Coefficient& g_j = g.coefficient(Variable(j));
            const dimension_type dj = 2*j;
            // Set for any ray the right limit in the case
            // of the binary constraints.
            if (g_i < g_j)
              // Hyperplane: X_i - X_j >= +Inf.
              assign_r(x_i[dj], PLUS_INFINITY, ROUND_NOT_NEEDED);
            if (g_i > g_j)
              // Hyperplane: X_i - X_j <= +Inf.
              assign_r(x_ii[dj+1], PLUS_INFINITY, ROUND_NOT_NEEDED);
            if (g_i < -g_j)
              // Hyperplane: X_i + X_j >= +Inf.
              assign_r(x_i[dj+1], PLUS_INFINITY, ROUND_NOT_NEEDED);
            if (g_i > -g_j)
              // Hyperplane: X_i + X_j <= +Inf.
              assign_r(x_ii[dj], PLUS_INFINITY, ROUND_NOT_NEEDED);
          }
          // Case: unary constraints.
          if (g_i < 0)
            // Hyperplane: X_i  = +Inf.
            assign_r(x_i[di+1], PLUS_INFINITY, ROUND_NOT_NEEDED);
          if (g_i > 0)
            // Hyperplane: X_i  = +Inf.
            assign_r(x_ii[di], PLUS_INFINITY, ROUND_NOT_NEEDED);
        }
      break;
    default:
      // Points and closure points already dealt with.
      break;
    }
  }
  set_strongly_closed();
  assert(OK());
}

template <typename T>
void
Octagonal_Shape<T>::add_constraint(const Constraint& c) {
  const dimension_type c_space_dim = c.space_dimension();
  // Dimension-compatibility check.
  if (c_space_dim > space_dim)
    throw_dimension_incompatible("add_constraint(c)", c);

  // Get rid of strict inequalities.
  if (c.is_strict_inequality()) {
    if (c.is_inconsistent()) {
      set_empty();
      return;
    }
    if (c.is_tautological())
      return;
    // Nontrivial strict inequalities are not allowed.
    throw_generic("add_constraint(c)", "strict inequalities are not allowed");
  }

  dimension_type num_vars = 0;
  dimension_type i = 0;
  dimension_type j = 0;
  PPL_DIRTY_TEMP_COEFFICIENT(coeff);
  PPL_DIRTY_TEMP_COEFFICIENT(term);
  // Constraints that are not octagonal differences are not allowed.
  if (!extract_octagonal_difference(c, c_space_dim, num_vars,
                                    i, j, coeff, term))
    throw_generic("add_constraint(c)",
                  "c is not an octagonal constraint");

  if (num_vars == 0) {
    // Dealing with a trivial constraint (not a strict inequality).
    if (c.inhomogeneous_term() < 0
        || (c.is_equality() && c.inhomogeneous_term() != 0))
      set_empty();
    return;
  }

  // Select the cell to be modified for the "<=" part of constraint.
  typename OR_Matrix<N>::row_iterator i_iter = matrix.row_begin() + i;
  typename OR_Matrix<N>::row_reference_type m_i = *i_iter;
  N& m_i_j = m_i[j];
  // Set `coeff' to the absolute value of itself.
  if (coeff < 0)
    neg_assign(coeff);

  bool is_oct_changed = false;
  // Compute the bound for `m_i_j', rounding towards plus infinity.
  PPL_DIRTY_TEMP(N, d);
  div_round_up(d, term, coeff);
  if (m_i_j > d) {
    m_i_j = d;
    is_oct_changed = true;
  }

  if (c.is_equality()) {
    // Select the cell to be modified for the ">=" part of constraint.
    if (i % 2 == 0)
      ++i_iter;
    else
      --i_iter;

    typename OR_Matrix<N>::row_reference_type m_ci = *i_iter;
    dimension_type cj = coherent_index(j);
    N& m_ci_cj = m_ci[cj];
    // Also compute the bound for `m_ci_cj', rounding towards plus infinity.
    neg_assign(term);
    div_round_up(d, term, coeff);
    if (m_ci_cj > d) {
      m_ci_cj = d;
      is_oct_changed = true;
    }
  }

  // This method does not preserve closure.
  if (is_oct_changed && marked_strongly_closed())
    reset_strongly_closed();
  assert(OK());
}

template <typename T>
void
Octagonal_Shape<T>::add_congruence(const Congruence& cg) {
  const dimension_type cg_space_dim = cg.space_dimension();
  // Dimension-compatibility check:
  // the dimension of `cg' can not be greater than space_dim.
  if (space_dimension() < cg_space_dim)
    throw_dimension_incompatible("add_congruence(cg)", cg);

  // Handle the case of proper congruences first.
  if (cg.is_proper_congruence()) {
    if (cg.is_tautological())
      return;
    if (cg.is_inconsistent()) {
      set_empty();
      return;
    }
    // Non-trivial and proper congruences are not allowed.
    throw_generic("add_congruence(cg)",
                  "cg is a non-trivial, proper congruence");
  }

  assert(cg.is_equality());
  Constraint c(cg);
  add_constraint(c);
}

template <typename T>
void
Octagonal_Shape<T>::refine_no_check(const Constraint& c) {
  assert(!marked_empty());
  const dimension_type c_space_dim = c.space_dimension();
  assert(c_space_dim <= space_dim);

  dimension_type num_vars = 0;
  dimension_type i = 0;
  dimension_type j = 0;
  PPL_DIRTY_TEMP_COEFFICIENT(coeff);
  PPL_DIRTY_TEMP_COEFFICIENT(term);
  // Constraints that are not octagonal differences are ignored.
  if (!extract_octagonal_difference(c, c_space_dim, num_vars,
                                    i, j, coeff, term))
    return;

  if (num_vars == 0) {
    const Coefficient& c_inhomo = c.inhomogeneous_term();
    // Dealing with a trivial constraint (maybe a strict inequality).
    if (c_inhomo < 0
        || (c_inhomo != 0 && c.is_equality())
        || (c_inhomo == 0 && c.is_strict_inequality()))
      set_empty();
    return;
  }

  // Select the cell to be modified for the "<=" part of constraint.
  typename OR_Matrix<N>::row_iterator i_iter = matrix.row_begin() + i;
  typename OR_Matrix<N>::row_reference_type m_i = *i_iter;
  N& m_i_j = m_i[j];
  // Set `coeff' to the absolute value of itself.
  if (coeff < 0)
    neg_assign(coeff);

  bool is_oct_changed = false;
  // Compute the bound for `m_i_j', rounding towards plus infinity.
  PPL_DIRTY_TEMP(N, d);
  div_round_up(d, term, coeff);
  if (m_i_j > d) {
    m_i_j = d;
    is_oct_changed = true;
  }

  if (c.is_equality()) {
    // Select the cell to be modified for the ">=" part of constraint.
    if (i % 2 == 0)
      ++i_iter;
    else
      --i_iter;

    typename OR_Matrix<N>::row_reference_type m_ci = *i_iter;
    dimension_type cj = coherent_index(j);
    N& m_ci_cj = m_ci[cj];
    // Also compute the bound for `m_ci_cj', rounding towards plus infinity.
    neg_assign(term);
    div_round_up(d, term, coeff);
    if (m_ci_cj > d) {
      m_ci_cj = d;
      is_oct_changed = true;
    }
  }

  // This method does not preserve closure.
  if (is_oct_changed && marked_strongly_closed())
    reset_strongly_closed();
  assert(OK());
}

template <typename T>
dimension_type
Octagonal_Shape<T>::affine_dimension() const {
  const dimension_type n_rows = matrix.num_rows();
  // A zero-space-dim shape always has affine dimension zero.
  if (n_rows == 0)
    return 0;

  // Strong closure is necessary to detect emptiness
  // and all (possibly implicit) equalities.
  strong_closure_assign();
  if (marked_empty())
    return 0;

  // The vector `leaders' is used to represent non-singular
  // equivalence classes:
  // `leaders[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> leaders;
  compute_leaders(leaders);

  // Due to the splitting of variables, the affine dimension is the
  // number of non-singular positive zero-equivalence classes.
  dimension_type affine_dim = 0;
  for (dimension_type i = 0; i < n_rows; i += 2)
    // Note: disregard the singular equivalence class.
    if (leaders[i] == i && leaders[i+1] == i+1)
      ++affine_dim;

  return affine_dim;
}

template <typename T>
Congruence_System
Octagonal_Shape<T>::minimized_congruences() const {
  // Strong closure is necessary to detect emptiness
  // and all (possibly implicit) equalities.
  strong_closure_assign();
  const dimension_type space_dim = space_dimension();
  Congruence_System cgs;
  if (space_dim == 0) {
    if (marked_empty())
      cgs = Congruence_System::zero_dim_empty();
  }
  else if (marked_empty())
    cgs.insert((0*Variable(space_dim-1) %= 1) / 0);
  else {
    // KLUDGE: in the future `cgs' will be constructed of the right dimension.
    // For the time being, we force the dimension with the following line.
    cgs.insert(0*Variable(space_dim-1) == 0);

    // The vector `leaders' is used to represent equivalence classes:
    // `leaders[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> leaders;
    compute_leaders(leaders);

    PPL_DIRTY_TEMP_COEFFICIENT(num);
    PPL_DIRTY_TEMP_COEFFICIENT(den);
    for (dimension_type i = 0, i_end = 2*space_dim; i != i_end; i += 2) {
      const dimension_type lead_i = leaders[i];
      if (i == lead_i) {
        if (leaders[i+1] == i)
          // `i' is the leader of the singular equivalence class.
          goto singular;
        else
          // `i' is the leader of a non-singular equivalence class.
          continue;
      }
      else {
        // `i' is not a leader.
        if (leaders[i+1] == lead_i)
          // `i' belongs to the singular equivalence class.
          goto singular;
        else
          // `i' does not belong to the singular equivalence class.
          goto non_singular;
      }

    singular:
      // `i' belongs to the singular equivalence class:
      // we have a unary equality constraint.
      {
        const Variable x(i/2);
        const N& c_ii_i = matrix[i+1][i];
#ifndef NDEBUG
        const N& c_i_ii = matrix[i][i+1];
        assert(is_additive_inverse(c_i_ii, c_ii_i));
#endif
        numer_denom(c_ii_i, num, den);
        den *= 2;
        cgs.insert(den*x == num);
      }
      continue;

    non_singular:
      // `i' does not belong to the singular equivalence class.
      // we have a binary equality constraint.
      {
        const N& c_i_li = matrix[i][lead_i];
#ifndef NDEBUG
        const N& c_ii_lii = matrix[i+1][coherent_index(lead_i)];
        assert(is_additive_inverse(c_ii_lii, c_i_li));
#endif
        const Variable x(lead_i/2);
        const Variable y(i/2);
        numer_denom(c_i_li, num, den);
        if (lead_i % 2 == 0)
          cgs.insert(den*x - den*y == num);
        else
          cgs.insert(den*x + den*y + num == 0);
      }
      continue;
    }
  }
  return cgs;
}

template <typename T>
void
Octagonal_Shape<T>::concatenate_assign(const Octagonal_Shape& y) {
  // If `y' is an empty 0-dim space octagon, let `*this' become empty.
  // If `y' is an universal 0-dim space octagon, we simply return.
  if (y.space_dim == 0) {
    if (y.marked_empty())
      set_empty();
    return;
  }

  // If `*this' is an empty 0-dim space octagon, then it is sufficient
  // to adjust the dimension of the vector space.
  if (space_dim == 0 && marked_empty()) {
    add_space_dimensions_and_embed(y.space_dim);
    return;
  }

  // This is the old number of rows in the matrix. It is equal to
  // the first index of columns to change.
  dimension_type old_num_rows = matrix.num_rows();
  // First we increase the space dimension of `*this' by adding
  // `y.space_dimension()' new dimensions.
  // The matrix for the new octagon is obtained
  // by leaving the old system of constraints in the upper left-hand side
  // (where they are at the present) and placing the constraints of `y' in the
  // lower right-hand side.
  add_space_dimensions_and_embed(y.space_dim);
  typename OR_Matrix<N>::const_element_iterator
    y_it = y.matrix.element_begin();
  for(typename OR_Matrix<N>::row_iterator i = matrix.row_begin()+old_num_rows,
        matrix_row_end = matrix.row_end(); i != matrix_row_end; ++i) {
    typename OR_Matrix<N>::row_reference_type r = *i;
    dimension_type rs_i = i.row_size();
    for (dimension_type j = old_num_rows; j < rs_i; ++j, ++y_it)
      r[j] = *y_it;
  }

  // The concatenation doesn't preserve the closure.
  if (marked_strongly_closed())
    reset_strongly_closed();
  assert(OK());
}

template <typename T>
bool
Octagonal_Shape<T>::contains(const Octagonal_Shape& y) const {
  // Dimension-compatibility check.
  if (space_dim != y.space_dim)
    throw_dimension_incompatible("contains(y)", y);

  // The zero-dimensional universe octagon contains any other
  // dimension-compatible octagon.
  // The zero-dimensional empty octagon only contains another
  // zero-dimensional empty octagon.
  if (space_dim == 0) {
    if (!marked_empty())
      return true;
    else
      return y.marked_empty();
  }

  // `y' needs to be transitively closed.
  y.strong_closure_assign();
  // An empty octagon is in any other dimension-compatible octagons.
  if (y.marked_empty())
    return true;

  // `*this' contains `y' if and only if every element of `*this'
  // is greater than or equal to the correspondent one of `y'.
  for (typename OR_Matrix<N>::const_element_iterator
         i = matrix.element_begin(), j = y.matrix.element_begin(),
         matrix_element_end = matrix.element_end(); i != matrix_element_end; ++i, ++j)
    if (*i < *j)
      return false;
  return true;
}

template <typename T>
bool
Octagonal_Shape<T>::is_disjoint_from(const Octagonal_Shape& y) const {
  // Dimension-compatibility check.
  if (space_dim != y.space_dim)
    throw_dimension_incompatible("is_disjoint_from(y)", y);

  // If one Octagonal_Shape is empty, the Octagonal_Shapes are disjoint.
  strong_closure_assign();
  if (marked_empty())
    return true;
  y.strong_closure_assign();
  if (y.marked_empty())
    return true;

  // Two Octagonal_Shapes are disjoint if and only if their intersection
  // is empty, i.e., if and only if there exists a variable such that
  // the upper bound of the constraint on that variable in the first
  // Octagonal_Shape is strictly less than the lower bound of
  // the correspomding constraint in the second Octagonal_Shape or vice versa.

  const dimension_type n_rows = matrix.num_rows();

  typedef typename OR_Matrix<N>::const_row_iterator Row_Iterator;
  typedef typename OR_Matrix<N>::const_row_reference_type Row_Reference;

  const Row_Iterator m_begin = matrix.row_begin();
  const Row_Iterator m_end = matrix.row_end();

  const Row_Iterator y_begin = y.matrix.row_begin();

  PPL_DIRTY_TEMP(N, neg_y_ci_cj);
  for (Row_Iterator i_iter = m_begin; i_iter != m_end; ++i_iter) {
    const dimension_type i = i_iter.index();
    const dimension_type ci = coherent_index(i);
    const dimension_type rs_i = i_iter.row_size();
    Row_Reference m_i = *i_iter;
    for (dimension_type j = 0; j < n_rows; ++j) {
      const dimension_type cj = coherent_index(j);
      Row_Reference m_cj = *(m_begin + cj);
      const N& m_i_j = (j < rs_i) ? m_i[j] : m_cj[ci];
      Row_Reference y_ci = *(y_begin + ci);
      Row_Reference y_j = *(y_begin + j);
      const N& y_ci_cj = (j < rs_i) ? y_ci[cj] : y_j[i];
      neg_assign_r(neg_y_ci_cj, y_ci_cj, ROUND_UP);
      if (m_i_j < neg_y_ci_cj)
        return true;
    }
  }
  return false;
}

template <typename T>
bool
Octagonal_Shape<T>::is_universe() const {
  // An empty octagon isn't, of course, universe.
  if (marked_empty())
    return false;

  // If the octagon is non-empty and zero-dimensional,
  // then it is necessarily the universe octagon.
  if (space_dim == 0)
    return true;

  // An universe octagon can only contains trivial  constraints.
  for (typename OR_Matrix<N>::const_element_iterator
         i = matrix.element_begin(), matrix_element_end = matrix.element_end();
       i != matrix_element_end;
       ++i)
    if (!is_plus_infinity(*i))
      return false;

  return true;
}

template <typename T>
bool
Octagonal_Shape<T>::is_bounded() const {
  strong_closure_assign();
  // A zero-dimensional or empty octagon is bounded.
  if (marked_empty() || space_dim == 0)
    return true;

  // A bounded octagon never can contains trivial constraints.
  for (typename OR_Matrix<N>::const_row_iterator i = matrix.row_begin(),
         matrix_row_end = matrix.row_end(); i != matrix_row_end; ++i) {
    typename OR_Matrix<N>::const_row_reference_type x_i = *i;
    const dimension_type i_index = i.index();
    for (dimension_type j = i.row_size(); j-- > 0; )
      if (i_index != j)
        if (is_plus_infinity(x_i[j]))
          return false;
  }

  return true;
}

template <typename T>
bool
Octagonal_Shape<T>::contains_integer_point() const {
  // Force strong closure.
  if (is_empty())
    return false;
  const dimension_type space_dim = space_dimension();
  if (space_dim == 0)
    return true;

  // A strongly closed and consistent Octagonal_Shape defined by
  // integer constraints can only be empty due to tight coeherence.
  if (std::numeric_limits<T>::is_integer)
    return !tight_coherence_would_make_empty();

  // Build an integer Octagonal_Shape oct_z with bounds at least as
  // tight as those in *this and then recheck for emptiness, also
  // exploiting tight-coherence.
  Octagonal_Shape<mpz_class> oct_z(space_dim);
  oct_z.reset_strongly_closed();

  typedef Octagonal_Shape<mpz_class>::N Z;
  PPL_DIRTY_TEMP(N, tmp);
  bool all_integers = true;
  typename OR_Matrix<N>::const_element_iterator x_i = matrix.element_begin();
  for (typename OR_Matrix<Z>::element_iterator
         z_i = oct_z.matrix.element_begin(),
         z_end = oct_z.matrix.element_end(); z_i != z_end; ++z_i, ++x_i) {
    const N& d = *x_i;
    if (is_plus_infinity(d))
      continue;
    if (is_integer(d))
      assign_r(*z_i, d, ROUND_NOT_NEEDED);
    else {
      all_integers = false;
      Z& d_z = *z_i;
      // Copy d into d_z, but rounding downwards.
      neg_assign_r(tmp, d, ROUND_NOT_NEEDED);
      assign_r(d_z, tmp, ROUND_UP);
      neg_assign_r(d_z, d_z, ROUND_NOT_NEEDED);
    }
  }
  // Restore strong closure.
  if (all_integers)
    // oct_z unchanged, so it is still strongly closed.
    oct_z.set_strongly_closed();
  else {
    // oct_z changed: recompute strong closure.
    oct_z.strong_closure_assign();
    if (oct_z.marked_empty())
      return false;
  }
  return !oct_z.tight_coherence_would_make_empty();
}

template <typename T>
bool
Octagonal_Shape<T>::constrains(const Variable var) const {
  // `var' should be one of the dimensions of the polyhedron.
  const dimension_type var_space_dim = var.space_dimension();
  if (space_dimension() < var_space_dim)
    throw_dimension_incompatible("constrains(v)", "v", var);

  // A polyhedron known to be empty constrains all variables.
  // (Note: do not force emptiness check _yet_)
  if (marked_empty())
    return true;

  // Check whether `var' is syntactically constrained.
  const dimension_type n_v = 2*(var_space_dim - 1);
  typename OR_Matrix<N>::const_row_iterator m_iter = matrix.row_begin() + n_v;
  typename OR_Matrix<N>::const_row_reference_type r_v = *m_iter;
  typename OR_Matrix<N>::const_row_reference_type r_cv = *(++m_iter);
  for (dimension_type h = m_iter.row_size(); h-- > 0; ) {
    if (!is_plus_infinity(r_v[h]) || !is_plus_infinity(r_cv[h]))
      return true;
  }
  ++m_iter;
  for (typename OR_Matrix<N>::const_row_iterator m_end = matrix.row_end();
       m_iter != m_end; ++m_iter) {
    typename OR_Matrix<N>::const_row_reference_type r = *m_iter;
    if (!is_plus_infinity(r[n_v]) || !is_plus_infinity(r[n_v+1]))
      return true;
  }

  // `var' is not syntactically constrained:
  // now force an emptiness check.
  return is_empty();
}

template <typename T>
bool
Octagonal_Shape<T>::is_strong_coherent() const {
  // This method is only used by method OK() so as to check if a
  // strongly closed matrix is also strong-coherent, as it must be.
  const dimension_type num_rows = matrix.num_rows();

  // Allocated here once and for all.
  PPL_DIRTY_TEMP(N, semi_sum);
  // The strong-coherence is: for every indexes i and j (and i != j)
  // matrix[i][j] <= (matrix[i][ci] + matrix[cj][j])/2
  // where ci = i + 1, if i is even number or
  //       ci = i - 1, if i is odd.
  // Ditto for cj.
  for (dimension_type i = num_rows; i-- > 0; ) {
    typename OR_Matrix<N>::const_row_iterator iter = matrix.row_begin() + i;
    typename OR_Matrix<N>::const_row_reference_type m_i = *iter;
    const N& m_i_ci = m_i[coherent_index(i)];
    for (dimension_type j = matrix.row_size(i); j-- > 0; )
      // Note: on the main diagonal only PLUS_INFINITY can occur.
      if (i != j) {
        const N& m_cj_j = matrix[coherent_index(j)][j];
        if (!is_plus_infinity(m_i_ci)
            && !is_plus_infinity(m_cj_j)) {
          // Compute (m_i_ci + m_cj_j)/2 into `semi_sum',
          // rounding the result towards plus infinity.
          add_assign_r(semi_sum, m_i_ci, m_cj_j, ROUND_UP);
          div2exp_assign_r(semi_sum, semi_sum, 1, ROUND_UP);
          if (m_i[j] > semi_sum)
            return false;
        }
      }
  }
  return true;
}

template <typename T>
bool
Octagonal_Shape<T>::is_strongly_reduced() const {
  // This method is only used in assertions: efficiency is not a must.

  // An empty octagon is already transitively reduced.
  if (marked_empty())
    return true;

  Octagonal_Shape x = *this;
  // The matrix representing an OS is strongly reduced if, by removing
  // any constraint, the resulting matrix describes a different OS.
  for (typename OR_Matrix<N>::const_row_iterator iter = matrix.row_begin(),
         matrix_row_end = matrix.row_end(); iter != matrix_row_end; ++iter) {
    typename OR_Matrix<N>::const_row_reference_type m_i = *iter;
    const dimension_type i = iter.index();
    for (dimension_type j = iter.row_size(); j-- > 0; ) {
      if (!is_plus_infinity(m_i[j])) {
        Octagonal_Shape x_copy = *this;
        assign_r(x_copy.matrix[i][j], PLUS_INFINITY, ROUND_NOT_NEEDED);
        if (x == x_copy)
          return false;
      }
    }
  }
  // The octagon is just reduced.
  return true;
}

template <typename T>
bool
Octagonal_Shape<T>::bounds(const Linear_Expression& expr,
                           const bool from_above) const {
  // The dimension of `expr' should not be greater than the dimension
  // of `*this'.
  const dimension_type expr_space_dim = expr.space_dimension();
  if (space_dim < expr_space_dim)
    throw_dimension_incompatible((from_above
                                  ? "bounds_from_above(e)"
                                  : "bounds_from_below(e)"), "e", expr);
  strong_closure_assign();

  // A zero-dimensional or empty octagon bounds everything.
  if (space_dim == 0 || marked_empty())
    return true;

  // The constraint `c' is used to check if `expr' is an octagonal difference
  // and, in this case, to select the cell.
  const Constraint& c = (from_above) ? expr <= 0 : expr >= 0;
  dimension_type num_vars = 0;
  dimension_type i = 0;
  dimension_type j = 0;
  PPL_DIRTY_TEMP_COEFFICIENT(coeff);
  PPL_DIRTY_TEMP_COEFFICIENT(term);
  if (extract_octagonal_difference(c, c.space_dimension(), num_vars,
                                   i, j, coeff, term)) {
    if (num_vars == 0)
      return true;
    // Select the cell to be checked.
    typename OR_Matrix<N>::const_row_iterator i_iter = matrix.row_begin() + i;
    typename OR_Matrix<N>::const_row_reference_type m_i = *i_iter;
    return !is_plus_infinity(m_i[j]);
  }
  else {
    // `c' is not an octagonal constraint: use the MIP solver.
    Optimization_Mode mode_bounds =
      from_above ? MAXIMIZATION : MINIMIZATION;
    MIP_Problem mip(space_dim, constraints(), expr, mode_bounds);
    return (mip.solve() == OPTIMIZED_MIP_PROBLEM);
  }
}

template <typename T>
bool
Octagonal_Shape<T>::max_min(const Linear_Expression& expr,
                            const bool maximize,
                            Coefficient& ext_n, Coefficient& ext_d,
                            bool& included) const {
  // The dimension of `expr' should not be greater than the dimension
  // of `*this'.
  const dimension_type expr_space_dim = expr.space_dimension();
  if (space_dim < expr_space_dim)
    throw_dimension_incompatible((maximize
                                  ? "maximize(e, ...)"
                                  : "minimize(e, ...)"), "e", expr);
  // Deal with zero-dim octagons first.
  if (space_dim == 0) {
    if (marked_empty())
      return false;
    else {
      ext_n = expr.inhomogeneous_term();
      ext_d = 1;
      included = true;
      return true;
    }
  }

  strong_closure_assign();
  // For an empty OS we simply return false.
  if (marked_empty())
    return false;

  // The constraint `c' is used to check if `expr' is an octagonal difference
  // and, in this case, to select the cell.
  const Constraint& c = (maximize) ? expr <= 0 : expr >= 0;
  dimension_type num_vars = 0;
  dimension_type i = 0;
  dimension_type j = 0;
  PPL_DIRTY_TEMP_COEFFICIENT(coeff);
  PPL_DIRTY_TEMP_COEFFICIENT(term);
  if (!extract_octagonal_difference(c, c.space_dimension(), num_vars,
                                    i, j, coeff, term)) {
    // `c' is not an octagonal constraint: use the MIP solver.
    Optimization_Mode max_min = (maximize) ? MAXIMIZATION : MINIMIZATION;
    MIP_Problem mip(space_dim, constraints(), expr, max_min);
    if (mip.solve() == OPTIMIZED_MIP_PROBLEM) {
      mip.optimal_value(ext_n, ext_d);
      included = true;
      return true;
    }
    else
      // Here`expr' is unbounded in `*this'.
      return false;
  }
  else {
    // `c' is an octagonal constraint.
    if (num_vars == 0) {
      ext_n = expr.inhomogeneous_term();
      ext_d = 1;
      included = true;
      return true;
    }

    // Select the cell to be checked.
    typename OR_Matrix<N>::const_row_iterator i_iter = matrix.row_begin() + i;
    typename OR_Matrix<N>::const_row_reference_type m_i = *i_iter;
    PPL_DIRTY_TEMP(N, d);
    if (!is_plus_infinity(m_i[j])) {
      const Coefficient& b = expr.inhomogeneous_term();
      PPL_DIRTY_TEMP_COEFFICIENT(minus_b);
      neg_assign(minus_b, b);
      const Coefficient& sc_b = maximize ? b : minus_b;
      assign_r(d, sc_b, ROUND_UP);
      // Set `coeff_expr' to the absolute value of coefficient of a variable
      // of `expr'.
      PPL_DIRTY_TEMP(N, coeff_expr);
      const Coefficient& coeff_i = expr.coefficient(Variable(i/2));
      const int sign_i = sgn(coeff_i);
      if (sign_i > 0)
        assign_r(coeff_expr, coeff_i, ROUND_UP);
      else {
        PPL_DIRTY_TEMP_COEFFICIENT(minus_coeff_i);
        neg_assign(minus_coeff_i, expr.coefficient(Variable(i/2)));
        assign_r(coeff_expr, minus_coeff_i, ROUND_UP);
      }
      // Approximating the maximum/minimum of `expr'.
      if (num_vars == 1) {
        PPL_DIRTY_TEMP(N, m_i_j);
        div2exp_assign_r(m_i_j, m_i[j], 1, ROUND_UP);
        add_mul_assign_r(d, coeff_expr, m_i_j, ROUND_UP);
      }
      else
        add_mul_assign_r(d, coeff_expr, m_i[j], ROUND_UP);
      numer_denom(d, ext_n, ext_d);
      if (!maximize)
        neg_assign(ext_n);
      included = true;
      return true;
    }

    // The `expr' is unbounded.
    return false;
  }
}

template <typename T>
bool
Octagonal_Shape<T>::max_min(const Linear_Expression& expr,
                            const bool maximize,
                            Coefficient& ext_n, Coefficient& ext_d,
                            bool& included, Generator& g) const {
  // The dimension of `expr' should not be greater than the dimension
  // of `*this'.
  const dimension_type expr_space_dim = expr.space_dimension();
  if (space_dim < expr_space_dim)
    throw_dimension_incompatible((maximize
                                  ? "maximize(e, ...)"
                                  : "minimize(e, ...)"), "e", expr);
  // Deal with zero-dim octagons first.
  if (space_dim == 0) {
    if (marked_empty())
      return false;
    else {
      ext_n = expr.inhomogeneous_term();
      ext_d = 1;
      included = true;
      g = point();
      return true;
    }
  }

  strong_closure_assign();
  // For an empty OS we simply return false.
  if (marked_empty())
    return false;
  if (!is_universe()) {
    // We use MIP_Problems to handle constraints that are not
    // octagonal difference.
    Optimization_Mode max_min = (maximize) ? MAXIMIZATION : MINIMIZATION;
    MIP_Problem mip(space_dim, constraints(), expr, max_min);
    if (mip.solve() == OPTIMIZED_MIP_PROBLEM) {
      g = mip.optimizing_point();
      mip.evaluate_objective_function(g, ext_n, ext_d);
      included = true;
      return true;
    }
  }
  // The `expr' is unbounded.
  return false;
}

template <typename T>
Poly_Con_Relation
Octagonal_Shape<T>::relation_with(const Congruence& cg) const {
  dimension_type cg_space_dim = cg.space_dimension();

  // Dimension-compatibility check.
  if (cg_space_dim > space_dim) {
    throw_dimension_incompatible("relation_with(cg)", cg);
  }

  // If the congruence is an equality,
  // find the relation with the equivalent equality constraint.
  if (cg.is_equality()) {
    Constraint c(cg);
    return relation_with(c);
  }

  strong_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 (cg.is_inconsistent())
      return Poly_Con_Relation::is_disjoint();
    else if (cg.inhomogeneous_term() % cg.modulus() == 0)
      return Poly_Con_Relation::saturates()
        && Poly_Con_Relation::is_included();
  }

  PPL_DIRTY_TEMP(Coefficient, min_num);
  PPL_DIRTY_TEMP(Coefficient, min_den);
  bool min_included;
  PPL_DIRTY_TEMP_COEFFICIENT(mod);
  mod = cg.modulus();
  Linear_Expression le;
  for (dimension_type i = cg_space_dim; i-- > 0; )
    le += cg.coefficient(Variable(i)) * Variable(i);
  bool bounded_below = minimize(le, min_num, min_den, min_included);

  if (!bounded_below)
    return Poly_Con_Relation::strictly_intersects();

  PPL_DIRTY_TEMP_COEFFICIENT(v);
  PPL_DIRTY_TEMP_COEFFICIENT(lower_num);
  PPL_DIRTY_TEMP_COEFFICIENT(lower_den);
  PPL_DIRTY_TEMP_COEFFICIENT(lower);
  assign_r(lower_num, min_num, ROUND_NOT_NEEDED);
  assign_r(lower_den, min_den, ROUND_NOT_NEEDED);
  neg_assign(v, cg.inhomogeneous_term());
  lower = lower_num / lower_den;
  v += ((lower / mod) * mod);
  if (v * lower_den < lower_num)
    v += mod;
  const Constraint& c(le == v);
  return relation_with(c);
}

template <typename T>
Poly_Con_Relation
Octagonal_Shape<T>::relation_with(const Constraint& c) const {
  dimension_type c_space_dim = c.space_dimension();

  // Dimension-compatibility check.
  if (c_space_dim > space_dim)
    throw_dimension_incompatible("relation_with(c)", c);

  // The closure needs to make explicit the implicit constraints.
  strong_closure_assign();

  if (marked_empty())
    return Poly_Con_Relation::saturates()
      && Poly_Con_Relation::is_included()
      && Poly_Con_Relation::is_disjoint();

  if (space_dim == 0) {
    // Trivially false zero-dimensional constraint.
    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();

    // Trivially true zero-dimensional constraint.
    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;
  PPL_DIRTY_TEMP_COEFFICIENT(coeff);
  PPL_DIRTY_TEMP_COEFFICIENT(c_term);
  if (!extract_octagonal_difference(c, c_space_dim, num_vars,
                                    i, j, coeff, c_term)) {
    // Constraints that are not octagonal differences.
    // Use maximize() and minimize() to do much of the work.

    // Find the linear expression for the constraint and use that to
    // find if the expression is bounded from above or below and if it
    // is, find the maximum and minimum values.
    Linear_Expression le;
    for (dimension_type k = c_space_dim; k-- > 0; ) {
      Variable vk(k);
      le += c.coefficient(vk) * vk;
    }
    PPL_DIRTY_TEMP(Coefficient, max_num);
    PPL_DIRTY_TEMP(Coefficient, max_den);
    bool max_included;
    PPL_DIRTY_TEMP(Coefficient, min_num);
    PPL_DIRTY_TEMP(Coefficient, min_den);
    bool min_included;
    bool bounded_above = maximize(le, max_num, max_den, max_included);
    bool bounded_below = minimize(le, min_num, min_den, min_included);
    if (!bounded_above) {
      if (!bounded_below)
        return Poly_Con_Relation::strictly_intersects();
      min_num += c.inhomogeneous_term() * min_den;
      switch (sgn(min_num)) {
      case 1:
        if (c.is_equality())
          return  Poly_Con_Relation::is_disjoint();
        return  Poly_Con_Relation::is_included();
      case 0:
        if (c.is_strict_inequality() || c.is_equality())
          return  Poly_Con_Relation::strictly_intersects();
        return  Poly_Con_Relation::is_included();
      case -1:
        return  Poly_Con_Relation::strictly_intersects();
      }
    }
    if (!bounded_below) {
      max_num += c.inhomogeneous_term() * max_den;
      switch (sgn(max_num)) {
      case 1:
        return  Poly_Con_Relation::strictly_intersects();
      case 0:
        if (c.is_strict_inequality())
          return  Poly_Con_Relation::is_disjoint();
        return  Poly_Con_Relation::strictly_intersects();
      case -1:
        return  Poly_Con_Relation::is_disjoint();
      }
    }
    else {
      max_num += c.inhomogeneous_term() * max_den;
      min_num += c.inhomogeneous_term() * min_den;
      switch (sgn(max_num)) {
      case 1:
        switch (sgn(min_num)) {
        case 1:
          if (c.is_equality())
            return  Poly_Con_Relation::is_disjoint();
          return  Poly_Con_Relation::is_included();
        case 0:
          if (c.is_equality())
            return  Poly_Con_Relation::strictly_intersects();
          if (c.is_strict_inequality())
            return  Poly_Con_Relation::strictly_intersects();
          return  Poly_Con_Relation::is_included();
        case -1:
          return  Poly_Con_Relation::strictly_intersects();
        }
     case 0:
        if (min_num == 0) {
          if (c.is_strict_inequality())
            return  Poly_Con_Relation::is_disjoint()
              && Poly_Con_Relation::saturates();
          return  Poly_Con_Relation::is_included()
            && Poly_Con_Relation::saturates();
        }
        if (c.is_strict_inequality())
          return  Poly_Con_Relation::is_disjoint();
        return  Poly_Con_Relation::strictly_intersects();
      case -1:
        return  Poly_Con_Relation::is_disjoint();
      }
    }
  }

  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:
      if (c.is_equality())
        return Poly_Con_Relation::is_disjoint();
      else
        return Poly_Con_Relation::is_included();
    }
  }

  // Select the cell to be checked for the "<=" part of constraint.
  typename OR_Matrix<N>::const_row_iterator i_iter = matrix.row_begin() + i;
  typename OR_Matrix<N>::const_row_reference_type m_i = *i_iter;
  const N& m_i_j = m_i[j];
  // Set `coeff' to the absolute value of itself.
  if (coeff < 0)
    neg_assign(coeff);

  // Select the cell to be checked for the ">=" part of constraint.
  // Select the right row of the cell.
  if (i % 2 == 0)
    ++i_iter;
  else
    --i_iter;
  typename OR_Matrix<N>::const_row_reference_type m_ci = *i_iter;
  const N& m_ci_cj = m_ci[coherent_index(j)];
  PPL_DIRTY_TEMP_COEFFICIENT(numer);
  PPL_DIRTY_TEMP_COEFFICIENT(denom);
  // The following variables of mpq_class type are used to be precise
  // when the octagon is defined by integer constraints.
  PPL_DIRTY_TEMP0(mpq_class, q_x);
  PPL_DIRTY_TEMP0(mpq_class, q_y);
  PPL_DIRTY_TEMP0(mpq_class, d);
  PPL_DIRTY_TEMP0(mpq_class, d1);
  PPL_DIRTY_TEMP0(mpq_class, c_den);
  PPL_DIRTY_TEMP0(mpq_class, q_den);
  assign_r(c_den, coeff, ROUND_NOT_NEEDED);
  assign_r(d, c_term, ROUND_NOT_NEEDED);
  neg_assign_r(d1, d, ROUND_NOT_NEEDED);
  div_assign_r(d, d, c_den, ROUND_NOT_NEEDED);
  div_assign_r(d1, d1, c_den, ROUND_NOT_NEEDED);

  if (is_plus_infinity(m_i_j)) {
    if (!is_plus_infinity(m_ci_cj)) {
      // `*this' is in the following form:
      // `-m_ci_cj <= v - u'.
      // In this case `*this' is disjoint from `c' if
      // `-m_ci_cj > d' (`-m_ci_cj >= d' if c is a strict inequality),
      // i.e. if `m_ci_cj < d1' (`m_ci_cj <= d1' if c is a strict inequality).
      numer_denom(m_ci_cj, numer, denom);
      assign_r(q_den, denom, ROUND_NOT_NEEDED);
      assign_r(q_y, numer, ROUND_NOT_NEEDED);
      div_assign_r(q_y, q_y, q_den, ROUND_NOT_NEEDED);
      if (q_y < d1)
        return Poly_Con_Relation::is_disjoint();
      if (q_y == d1 && c.is_strict_inequality())
        return Poly_Con_Relation::is_disjoint();
    }

    // In all other cases `*this' intersects `c'.
    return Poly_Con_Relation::strictly_intersects();
  }

  // Here `m_i_j' is not plus-infinity.
  numer_denom(m_i_j, numer, denom);
  assign_r(q_den, denom, ROUND_NOT_NEEDED);
  assign_r(q_x, numer, ROUND_NOT_NEEDED);
  div_assign_r(q_x, q_x, q_den, ROUND_NOT_NEEDED);

  if (!is_plus_infinity(m_ci_cj)) {
    numer_denom(m_ci_cj, numer, denom);
    assign_r(q_den, denom, ROUND_NOT_NEEDED);
    assign_r(q_y, numer, ROUND_NOT_NEEDED);
    div_assign_r(q_y, q_y, q_den, ROUND_NOT_NEEDED);
    if (q_x == d && q_y == d1) {
      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();
    }
    // `*this' is disjoint from `c' when
    // `m_ci_cj < d1' (`m_ci_cj <= d1' if `c' is a strict inequality).
    if (q_y < d1)
      return Poly_Con_Relation::is_disjoint();
    if (q_y == d1 && c.is_strict_inequality())
      return Poly_Con_Relation::is_disjoint();
  }

  // Here `m_ci_cj' can be also plus-infinity.
  // If `c' is an equality, `*this' is disjoint from `c' if
  // `m_i_j < d'.
  if (d > q_x) {
    if (c.is_equality())
      return Poly_Con_Relation::is_disjoint();
    else
      return Poly_Con_Relation::is_included();
  }

  if (d == q_x && c.is_nonstrict_inequality())
    return Poly_Con_Relation::is_included();

  // In all other cases `*this' intersects `c'.
  return Poly_Con_Relation::strictly_intersects();
}

template <typename T>
Poly_Gen_Relation
Octagonal_Shape<T>::relation_with(const Generator& g) const {
  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 closure needs to make explicit the implicit constraints and if the
  // octagon is empty.
  strong_closure_assign();

  // The empty octagon cannot subsume a generator.
  if (marked_empty())
    return Poly_Gen_Relation::nothing();

  // A universe octagon 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();
  const bool is_line_or_ray = g.is_line_or_ray();

  // The relation between the octagon and the given generator is obtained
  // checking if the generator satisfies all the constraints in the octagon.
  // 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 octagon.

  typedef typename OR_Matrix<N>::const_row_iterator Row_Iterator;
  typedef typename OR_Matrix<N>::const_row_reference_type Row_Reference;

  const Row_Iterator m_begin = matrix.row_begin();
  const Row_Iterator m_end = matrix.row_end();

  PPL_DIRTY_TEMP_COEFFICIENT(num);
  PPL_DIRTY_TEMP_COEFFICIENT(den);
  PPL_DIRTY_TEMP_COEFFICIENT(product);

  // We find in `*this' all the constraints.
  for (Row_Iterator i_iter = m_begin; i_iter != m_end; i_iter += 2) {
    dimension_type i = i_iter.index();
    Row_Reference m_i = *i_iter;
    Row_Reference m_ii = *(i_iter+1);
    const N& m_i_ii = m_i[i+1];
    const N& m_ii_i = m_ii[i];
    // We have the unary constraints.
    const Variable x(i/2);
    const Coefficient& g_coeff_x
      = (x.space_dimension() > g_space_dim)
      ? Coefficient_zero()
      : g.coefficient(x);
    if (is_additive_inverse(m_i_ii, m_ii_i)) {
      // The constraint has form ax = b.
      // To satisfy the constraint it's necessary that the scalar product
      // is not zero. The scalar product has the form:
      // 'den * g_coeff_x - num * g.divisor()'.
      numer_denom(m_ii_i, num, den);
      den *= 2;
      product = den * g_coeff_x;
      // Note that if the generator `g' is a line or a ray,
      // its divisor is zero.
      if (!is_line_or_ray) {
        neg_assign(num);
        add_mul_assign(product, num, g.divisor());
      }
      if (product != 0)
        return Poly_Gen_Relation::nothing();
    }
    // We have 0, 1 or 2 inequality constraints.
    else {
      if (!is_plus_infinity(m_i_ii)) {
        // The constraint has form -ax <= b.
        // If the generator is a line it's necessary to check if
        // the scalar product is not zero, if it is positive otherwise.
        numer_denom(m_i_ii, num, den);
        den *= -2;
        product = den * g_coeff_x;
        // Note that if the generator `g' is a line or a ray,
        // its divisor is zero.
        if (!is_line_or_ray) {
          neg_assign(num);
          add_mul_assign(product, num, g.divisor());
        }
        if (is_line && product != 0)
          return Poly_Gen_Relation::nothing();
        else
          // If the generator is not a line it's necessary to check
          // that the scalar product sign is not positive and the scalar
          // product has the form:
          // '-den * g.coeff_x - num * g.divisor()'.
          if (product > 0)
            return Poly_Gen_Relation::nothing();
      }
      if (!is_plus_infinity(m_ii_i)) {
        // The constraint has form ax <= b.
        numer_denom(m_ii_i, num, den);
        den *= 2;
        product = den * g_coeff_x;
         // Note that if the generator `g' is a line or a ray,
        // its divisor is zero.
        if (!is_line_or_ray) {
          neg_assign(num);
          add_mul_assign(product, num , g.divisor());
        }
        if (is_line && product != 0)
          return Poly_Gen_Relation::nothing();
        else
          // If the generator is not a line it's necessary to check
          // that the scalar product sign is not positive and the scalar
          // product has the form:
          // 'den * g_coeff_x - num * g.divisor()'.
          if (product > 0)
            return Poly_Gen_Relation::nothing();
      }
    }
  }

  // We have the binary constraints.
  for (Row_Iterator i_iter = m_begin ; i_iter != m_end; i_iter += 2) {
    dimension_type i = i_iter.index();
    Row_Reference m_i = *i_iter;
    Row_Reference m_ii = *(i_iter+1);
    for (dimension_type j = 0; j < i; j += 2) {
      const N& m_i_j = m_i[j];
      const N& m_ii_jj = m_ii[j+1];
      const N& m_ii_j = m_ii[j];
      const N& m_i_jj = m_i[j+1];
      const Variable x(j/2);
      const Variable y(i/2);
      const Coefficient& g_coeff_x
        = (x.space_dimension() > g_space_dim)
        ? Coefficient_zero()
        : g.coefficient(x);
      const Coefficient& g_coeff_y
        = (y.space_dimension() > g_space_dim)
        ? Coefficient_zero()
        : g.coefficient(y);

      const bool difference_is_equality = is_additive_inverse(m_ii_jj, m_i_j);
      if (difference_is_equality) {
        // The constraint has form ax - ay = b.
        // The scalar product has the form
        // 'den * coeff_x - den * coeff_y - num * g.divisor()'.
        // To satisfy the constraint it's necessary that the scalar product
        // is not zero.
        numer_denom(m_i_j, num, den);
        product = den * g_coeff_x;
        neg_assign(den);
        add_mul_assign(product, den, g_coeff_y);
        // Note that if the generator `g' is a line or a ray,
        // its divisor is zero.
        if (!is_line_or_ray) {
          neg_assign(num);
          add_mul_assign(product, num, g.divisor());
        }
        if (product != 0)
          return Poly_Gen_Relation::nothing();
      }
      else {
        if (!is_plus_infinity(m_i_j)) {
          // The constraint has form ax - ay <= b.
          // The scalar product has the form
          // 'den * coeff_x - den * coeff_y - num * g.divisor()'.
          // If the generator is not a line it's necessary to check
          // that the scalar product sign is not positive.
          numer_denom(m_i_j, num, den);
          product = den * g_coeff_x;
          neg_assign(den);
          add_mul_assign(product, den, g_coeff_y);
          // Note that if the generator `g' is a line or a ray,
          // its divisor is zero.
          if (!is_line_or_ray) {
            neg_assign(num);
            add_mul_assign(product, num, g.divisor());
          }
          if (is_line && product != 0)
            return Poly_Gen_Relation::nothing();
          else if (product > 0)
            return Poly_Gen_Relation::nothing();
        }
        if (!is_plus_infinity(m_ii_jj)) {
          // The constraint has form -ax + ay <= b.
          // The scalar product has the form
          // '-den * coeff_x + den * coeff_y - num * g.divisor()'.
          // If the generator is not a line it's necessary to check
          // that the scalar product sign is not positive.
          numer_denom(m_ii_jj, num, den);
          product = den * g_coeff_y;
          neg_assign(den);
          add_mul_assign(product, den, g_coeff_x);
          // Note that if the generator `g' is a line or a ray,
          // its divisor is zero.
          if (!is_line_or_ray) {
            neg_assign(num);
            add_mul_assign(product, num, g.divisor());
          }
          if (is_line && product != 0)
            return Poly_Gen_Relation::nothing();
          else if (product > 0)
            return Poly_Gen_Relation::nothing();
        }
      }

      const bool sum_is_equality = is_additive_inverse(m_i_jj, m_ii_j);
      if (sum_is_equality) {
        // The constraint has form ax + ay = b.
        // The scalar product has the form
        // 'den * coeff_x + den * coeff_y - num * g.divisor()'.
        // To satisfy the constraint it's necessary that the scalar product
        // is not zero.
        numer_denom(m_ii_j, num, den);
        product = den * g_coeff_x;
        add_mul_assign(product, den, g_coeff_y);
        // Note that if the generator `g' is a line or a ray,
        // its divisor is zero.
        if (!is_line_or_ray) {
          neg_assign(num);
          add_mul_assign(product, num, g.divisor());
        }
        if (product != 0)
          return Poly_Gen_Relation::nothing();
      }
      else {
        if (!is_plus_infinity(m_i_jj)) {
          // The constraint has form -ax - ay <= b.
          // The scalar product has the form
          // '-den * coeff_x - den * coeff_y - num * g.divisor()'.
          // If the generator is not a line it's necessary to check
          // that the scalar product sign is not positive.
          numer_denom(m_i_jj, num, den);
          neg_assign(den);
          product = den * g_coeff_x;
          add_mul_assign(product, den, g_coeff_y);
          // Note that if the generator `g' is a line or a ray,
          // its divisor is zero.
          if (!is_line_or_ray) {
            neg_assign(num);
            add_mul_assign(product, num, g.divisor());
          }
          if (is_line && product != 0)
            return Poly_Gen_Relation::nothing();
          else if (product > 0)
            return Poly_Gen_Relation::nothing();
        }
        if (!is_plus_infinity(m_ii_j)) {
          // The constraint has form ax + ay <= b.
          // The scalar product has the form
          // 'den * coeff_x + den * coeff_y - num * g.divisor()'.
          // If the generator is not a line it's necessary to check
          // that the scalar product sign is not positive.
          numer_denom(m_ii_j, num, den);
          product = den * g_coeff_x;
          add_mul_assign(product, den, g_coeff_y);
          // Note that if the generator `g' is a line or a ray,
          // its divisor is zero.
          if (!is_line_or_ray) {
            neg_assign(num);
            add_mul_assign(product, num, g.divisor());
          }
          if (is_line && product != 0)
            return Poly_Gen_Relation::nothing();
          else if (product > 0)
            return Poly_Gen_Relation::nothing();
        }
      }
    }
  }
  // If this point is reached the constraint 'g' satisfies
  // all the constraints in the octagon.
  return Poly_Gen_Relation::subsumes();
}

template <typename T>
void
Octagonal_Shape<T>::strong_closure_assign() const {
  // Do something only if necessary (zero-dim implies strong closure).
  if (marked_empty() || marked_strongly_closed() || space_dim == 0)
    return;

  // Even though the octagon will not change, its internal representation
  // is going to be modified by the closure algorithm.
  Octagonal_Shape& x = const_cast<Octagonal_Shape<T>&>(*this);

  typedef typename OR_Matrix<N>::row_iterator Row_Iterator;
  typedef typename OR_Matrix<N>::row_reference_type Row_Reference;

  const dimension_type n_rows = x.matrix.num_rows();
  const Row_Iterator m_begin = x.matrix.row_begin();
  const Row_Iterator m_end = x.matrix.row_end();

  // Fill the main diagonal with zeros.
  for (Row_Iterator i = m_begin; i != m_end; ++i) {
    assert(is_plus_infinity((*i)[i.index()]));
    assign_r((*i)[i.index()], 0, ROUND_NOT_NEEDED);
  }

  // This algorithm is given by two steps: the first one is a simple
  // adaptation of the `shortest-path closure' using the Floyd-Warshall
  // algorithm; the second one is the `strong-coherence' algorithm.
  // It is important to note that after the strong-coherence,
  // the octagon is still shortest-path closed and hence, strongly closed.

  // Recall that, given an index `h', we indicate with `ch' the coherent
  // index, i.e., the index such that:
  //   ch = h + 1, if h is an even number;
  //   ch = h - 1, if h is an odd number.

  typename OR_Matrix<N>::element_iterator iter_ij;
  std::vector<N> vec_k(n_rows);
  std::vector<N> vec_ck(n_rows);
  PPL_DIRTY_TEMP(N, sum1);
  PPL_DIRTY_TEMP(N, sum2);
  Row_Reference x_k;
  Row_Reference x_ck;
  Row_Reference x_i;
  Row_Reference x_ci;

  // Since the index `j' of the inner loop will go from 0 up to `i',
  // the three nested loops have to be executed twice.
  for (int twice = 0; twice < 2; ++twice) {

    Row_Iterator x_k_iter = m_begin;
    Row_Iterator x_i_iter = m_begin;
    for (dimension_type k = 0; k < n_rows; k += 2) {
      const dimension_type ck = k+1;
      // Re-initialize the element iterator.
      iter_ij = x.matrix.element_begin();
      // Compute the row references `x_k' and `x_ck'.
      x_k  = *x_k_iter;
      ++x_k_iter;
      x_ck = *x_k_iter;
      ++x_k_iter;

      for (dimension_type i = 0; i <= k; i += 2) {
        const dimension_type ci = i+1;
        // Storing x_k_i == x_ci_ck.
        vec_k[i] = x_k[i];
        // Storing x_k_ci == x_i_ck.
        vec_k[ci] = x_k[ci];
        // Storing x_ck_i == x_ci_k.
        vec_ck[i] = x_ck[i];
        // Storing x_ck_ci == x_i_k.
        vec_ck[ci] = x_ck[ci];
      }
      x_i_iter = x_k_iter;
      for (dimension_type i = k+2; i < n_rows; i += 2) {
        const dimension_type ci = i+1;
        x_i = *x_i_iter;
        ++x_i_iter;
        x_ci = *x_i_iter;
        ++x_i_iter;
        // Storing x_k_i == x_ci_ck.
        vec_k[i] = x_ci[ck];
        // Storing x_k_ci == x_i_ck.
        vec_k[ci] = x_i[ck];
        // Storing x_ck_i == x_ci_k.
        vec_ck[i] = x_ci[k];
        // Storing x_ck_ci == x_i_k.
        vec_ck[ci] = x_i[k];
      }

      for (dimension_type i = 0; i < n_rows; ++i) {
        const dimension_type ci = coherent_index(i);
        const N& vec_k_ci = vec_k[ci];
        const N& vec_ck_ci = vec_ck[ci];
        // Unfolding two iterations on `j': this ensures that
        // the loop exit condition `j <= i' is OK.
        for (dimension_type j = 0; j <= i; ) {
          // First iteration:
          // sum1 = x_i_k + x_k_j == x_ck_ci + x_k_j;
          // sum2 = x_i_ck + x_ck_j == x_k_ci + x_ck_j.
          add_assign_r(sum1, vec_ck_ci, vec_k[j], ROUND_UP);
          add_assign_r(sum2, vec_k_ci, vec_ck[j], ROUND_UP);
          min_assign(sum1, sum2);
          min_assign(*iter_ij, sum1);
          // Exiting the first iteration: loop index control.
          ++j;
          ++iter_ij;
          // Second iteration: ditto.
          add_assign_r(sum1, vec_ck_ci, vec_k[j], ROUND_UP);
          add_assign_r(sum2, vec_k_ci, vec_ck[j], ROUND_UP);
          min_assign(sum1, sum2);
          min_assign(*iter_ij, sum1);
          // Exiting the second iteration: loop index control.
          ++j;
          ++iter_ij;
        }
      }
    }
  }

  // Check for emptiness: the octagon is empty if and only if there is a
  // negative value in the main diagonal.
  for (Row_Iterator i = m_begin; i != m_end; ++i) {
    N& x_i_i = (*i)[i.index()];
    if (sgn(x_i_i) < 0) {
      x.set_empty();
      return;
    }
    else {
      assert(sgn(x_i_i) == 0);
      // Restore PLUS_INFINITY on the main diagonal.
      assign_r(x_i_i, PLUS_INFINITY, ROUND_NOT_NEEDED);
    }
  }

  // Step 2: we enforce the strong coherence.
  x.strong_coherence_assign();
  // The octagon is not empty and it is now strongly closed.
  x.set_strongly_closed();
}

template <typename T>
void
Octagonal_Shape<T>::strong_coherence_assign() {
  // The strong-coherence is: for every indexes i and j
  // m_i_j <= (m_i_ci + m_cj_j)/2
  // where ci = i + 1, if i is even number or
  //       ci = i - 1, if i is odd.
  // Ditto for cj.
  PPL_DIRTY_TEMP(N, semi_sum);
  for (typename OR_Matrix<N>::row_iterator i_iter = matrix.row_begin(),
         i_end = matrix.row_end(); i_iter != i_end; ++i_iter) {
    typename OR_Matrix<N>::row_reference_type x_i = *i_iter;
    const dimension_type i = i_iter.index();
    const N& x_i_ci = x_i[coherent_index(i)];
    // Avoid to do unnecessary sums.
    if (!is_plus_infinity(x_i_ci))
      for (dimension_type j = 0, rs_i = i_iter.row_size(); j < rs_i; ++j)
        if (i != j) {
          const N& x_cj_j = matrix[coherent_index(j)][j];
          if (!is_plus_infinity(x_cj_j)) {
            add_assign_r(semi_sum, x_i_ci, x_cj_j, ROUND_UP);
            div2exp_assign_r(semi_sum, semi_sum, 1, ROUND_UP);
            min_assign(x_i[j], semi_sum);
          }
        }
  }
}

template <typename T>
bool
Octagonal_Shape<T>::tight_coherence_would_make_empty() const {
  assert(std::numeric_limits<N>::is_integer);
  assert(marked_strongly_closed());
  const dimension_type space_dim = space_dimension();
  for (dimension_type i = 0; i < 2*space_dim; i += 2) {
    const dimension_type ci = i+1;
    const N& mat_i_ci = matrix[i][ci];
    if (!is_plus_infinity(mat_i_ci)
        // Check for oddness of `mat_i_ci'.
        && !is_even(mat_i_ci)
        // Check for zero-equivalence of `i' and `ci'.
        && is_additive_inverse(mat_i_ci, matrix[ci][i]))
      return true;
  }
  return false;
}

template <typename T>
void
Octagonal_Shape<T>
::incremental_strong_closure_assign(const Variable var) const {
  // `var' should be one of the dimensions of the octagon.
  if (var.id() >= space_dim)
    throw_dimension_incompatible("incremental_strong_closure_assign(v)",
                                 var.id());

  // Do something only if necessary.
  if (marked_empty() || marked_strongly_closed())
    return;

  Octagonal_Shape& x = const_cast<Octagonal_Shape<T>&>(*this);

  typedef typename OR_Matrix<N>::row_iterator Row_Iterator;
  typedef typename OR_Matrix<N>::row_reference_type Row_Reference;

  const Row_Iterator m_begin = x.matrix.row_begin();
  const Row_Iterator m_end = x.matrix.row_end();

  // Fill the main diagonal with zeros.
  for (Row_Iterator i = m_begin; i != m_end; ++i) {
    assert(is_plus_infinity((*i)[i.index()]));
    assign_r((*i)[i.index()], 0, ROUND_NOT_NEEDED);
  }

  // Using the incremental Floyd-Warshall algorithm.
  // Step 1: Improve all constraints on variable `var'.
  const dimension_type v = 2*var.id();
  const dimension_type cv = v+1;
  Row_Iterator v_iter = m_begin + v;
  Row_Iterator cv_iter = v_iter + 1;
  Row_Reference x_v = *v_iter;
  Row_Reference x_cv = *cv_iter;
  const dimension_type rs_v = v_iter.row_size();
  const dimension_type n_rows = x.matrix.num_rows();
  PPL_DIRTY_TEMP(N, sum);
  for (Row_Iterator k_iter = m_begin; k_iter != m_end; ++k_iter) {
    const dimension_type k = k_iter.index();
    const dimension_type ck = coherent_index(k);
    const dimension_type rs_k = k_iter.row_size();
    Row_Reference x_k = *k_iter;
    Row_Reference x_ck = (k % 2 != 0) ? *(k_iter-1) : *(k_iter+1);

    for (Row_Iterator i_iter = m_begin; i_iter != m_end; ++i_iter) {
      const dimension_type i = i_iter.index();
      const dimension_type ci = coherent_index(i);
      const dimension_type rs_i = i_iter.row_size();
      Row_Reference x_i = *i_iter;
      Row_Reference x_ci = (i % 2 != 0) ? *(i_iter-1) : *(i_iter+1);

      const N& x_i_k = (k < rs_i) ? x_i[k] : x_ck[ci];
      if (!is_plus_infinity(x_i_k)) {
        const N& x_k_v = (v < rs_k) ? x_k[v] : x_cv[ck];
        if (!is_plus_infinity(x_k_v)) {
          add_assign_r(sum, x_i_k, x_k_v, ROUND_UP);
          N& x_i_v = (v < rs_i) ? x_i[v] : x_cv[ci];
          min_assign(x_i_v, sum);
        }
        const N& x_k_cv = (cv < rs_k) ? x_k[cv] : x_v[ck];
        if (!is_plus_infinity(x_k_cv)) {
          add_assign_r(sum, x_i_k, x_k_cv, ROUND_UP);
          N& x_i_cv = (cv < rs_i) ? x_i[cv] : x_v[ci];
          min_assign(x_i_cv, sum);
        }
      }
      const N& x_k_i = (i < rs_k) ? x_k[i] : x_ci[ck];
      if (!is_plus_infinity(x_k_i)) {
        const N& x_v_k = (k < rs_v) ? x_v[k] : x_ck[cv];
        if (!is_plus_infinity(x_v_k)) {
          N& x_v_i = (i < rs_v) ? x_v[i] : x_ci[cv];
          add_assign_r(sum, x_v_k, x_k_i, ROUND_UP);
          min_assign(x_v_i, sum);
        }
        const N& x_cv_k = (k < rs_v) ? x_cv[k] : x_ck[v];
        if (!is_plus_infinity(x_cv_k)) {
          N& x_cv_i = (i < rs_v) ? x_cv[i] : x_ci[v];
          add_assign_r(sum, x_cv_k, x_k_i, ROUND_UP);
          min_assign(x_cv_i, sum);
        }
      }

    }
  }

  // Step 2: improve the other bounds by using the precise bounds
  // for the constraints on `var'.
  for (Row_Iterator i_iter = m_begin; i_iter != m_end; ++i_iter) {
    const dimension_type i = i_iter.index();
    const dimension_type ci = coherent_index(i);
    const dimension_type rs_i = i_iter.row_size();
    Row_Reference x_i = *i_iter;
    const N& x_i_v = (v < rs_i) ? x_i[v] : x_cv[ci];
    // TODO: see if it is possible to optimize this inner loop
    // by splitting it into several parts, so as to avoid
    // conditional expressions.
    for (dimension_type j = 0; j < n_rows; ++j) {
      const dimension_type cj = coherent_index(j);
      Row_Reference x_cj = *(m_begin+cj);
      N& x_i_j = (j < rs_i) ? x_i[j] : x_cj[ci];
      if (!is_plus_infinity(x_i_v)) {
        const N& x_v_j = (j < rs_v) ? x_v[j] : x_cj[cv];
        if (!is_plus_infinity(x_v_j)) {
          add_assign_r(sum, x_i_v, x_v_j, ROUND_UP);
          min_assign(x_i_j, sum);
        }
      }
      const N& x_i_cv = (cv < rs_i) ? x_i[cv] : x_v[ci];
      if (!is_plus_infinity(x_i_cv)) {
        const N& x_cv_j = (j < rs_v) ? x_cv[j] : x_cj[v];
        if (!is_plus_infinity(x_cv_j)) {
          add_assign_r(sum, x_i_cv, x_cv_j, ROUND_UP);
          min_assign(x_i_j, sum);
        }
      }
    }
  }

  // Check for emptiness: the octagon is empty if and only if there is a
  // negative value on the main diagonal.
  for (Row_Iterator i = m_begin; i != m_end; ++i) {
    N& x_i_i = (*i)[i.index()];
    if (sgn(x_i_i) < 0) {
      x.set_empty();
      return;
    }
    else {
      // Restore PLUS_INFINITY on the main diagonal.
      assert(sgn(x_i_i) == 0);
      assign_r(x_i_i, PLUS_INFINITY, ROUND_NOT_NEEDED);
    }
  }

  // Step 3: we enforce the strong coherence.
  x.strong_coherence_assign();
  // The octagon is not empty and it is now strongly closed.
  x.set_strongly_closed();
}

template <typename T>
void
Octagonal_Shape<T>
::compute_successors(std::vector<dimension_type>& successor) const {
  assert(!marked_empty() && marked_strongly_closed());
  assert(successor.size() == 0);
  // Variables are ordered according to their index.
  // The vector `successor' is used to indicate which variable
  // immediately follows a given one in the corresponding equivalence class.
  const dimension_type successor_size = matrix.num_rows();
  // Initially, each variable is successor of its own zero-equivalence class.
  successor.reserve(successor_size);
  for (dimension_type i = 0; i < successor_size; ++i)
    successor.push_back(i);
  // Now compute actual successors.
  for (dimension_type i = successor_size; i-- > 0; )  {
    typename OR_Matrix<N>::const_row_iterator i_iter = matrix.row_begin()+i;
    typename OR_Matrix<N>::const_row_reference_type m_i = *i_iter;
    typename OR_Matrix<N>::const_row_reference_type m_ci
      = (i % 2 != 0) ? *(i_iter-1) : *(i_iter+1);
    for (dimension_type j = 0; j < i; ++j) {
    //for (dimension_type j = i; j-- > 0; ) {
      dimension_type cj = coherent_index(j);
      if (is_additive_inverse(m_ci[cj], m_i[j]))
        // Choose as successor the variable having the greatest index.
        successor[j] = i;
    }
  }
}

template <typename T>
void
Octagonal_Shape<T>
::compute_leaders(std::vector<dimension_type>& leaders) const {
  assert(!marked_empty() && marked_strongly_closed());
  assert(leaders.size() == 0);
  // Variables are ordered according to their index.
  // The vector `leaders' is used to indicate the smallest variable
  // that belongs to the corresponding equivalence class.
  const dimension_type leader_size = matrix.num_rows();
  // Initially, each variable is leader of its own zero-equivalence class.
  leaders.reserve(leader_size);
  for (dimension_type i = 0; i < leader_size; ++i)
    leaders.push_back(i);
  // Now compute actual leaders.
  for (typename OR_Matrix<N>::const_row_iterator i_iter = matrix.row_begin(),
         matrix_row_end = matrix.row_end();
       i_iter != matrix_row_end; ++i_iter) {
    typename OR_Matrix<N>::const_row_reference_type m_i = *i_iter;
    dimension_type i = i_iter.index();
    typename OR_Matrix<N>::const_row_reference_type m_ci
      = (i % 2 != 0) ? *(i_iter-1) : *(i_iter+1);
    for (dimension_type j = 0; j < i; ++j) {
      dimension_type cj = coherent_index(j);
      if (is_additive_inverse(m_ci[cj], m_i[j]))
        // Choose as leader the variable having the smaller index.
        leaders[i] = leaders[j];
    }
  }
}

template <typename T>
void
Octagonal_Shape<T>
::compute_leaders(std::vector<dimension_type>& successor,
                  std::vector<dimension_type>& no_sing_leaders,
                  bool& exist_sing_class,
                  dimension_type& sing_leader) const {
  assert(!marked_empty() && marked_strongly_closed());
  assert(no_sing_leaders.size() == 0);
  dimension_type successor_size = successor.size();
  std::deque<bool> dealt_with(successor_size, false);
  for (dimension_type i = 0; i < successor_size; ++i) {
    dimension_type next_i = successor[i];
    if (!dealt_with[i]) {
      // The index is a leader.
      // Now check if it is a leader of a singular class or not.
      if (next_i == coherent_index(i)) {
        exist_sing_class = true;
        sing_leader = i;
      }
      else
        no_sing_leaders.push_back(i);
    }
    // The following index isn't a leader.
    dealt_with[next_i] = true;
  }
}

template <typename T>
void
Octagonal_Shape<T>::strong_reduction_assign() const {
  // Zero-dimensional octagonal shapes are necessarily reduced.
  if (space_dim == 0)
    return;
  strong_closure_assign();
  // If `*this' is empty, then there is nothing to reduce.
  if (marked_empty())
    return;

  // Detect non-redundant constraints.
  std::vector<Bit_Row> non_red;
  non_redundant_matrix_entries(non_red);

  // Throw away redundant constraints.
  Octagonal_Shape<T>& x = const_cast<Octagonal_Shape<T>&>(*this);
#ifndef NDEBUG
  const Octagonal_Shape x_copy_before(x);
#endif
  typename OR_Matrix<N>::element_iterator x_i = x.matrix.element_begin();
  for (dimension_type i = 0; i < 2 * space_dim; ++i) {
    const Bit_Row& non_red_i = non_red[i];
    for (dimension_type j = 0,
           j_end = OR_Matrix<N>::row_size(i); j < j_end; ++j, ++x_i) {
      if (!non_red_i[j])
        assign_r(*x_i, PLUS_INFINITY, ROUND_NOT_NEEDED);
    }
  }
  x.reset_strongly_closed();
#ifndef NDEBUG
  const Octagonal_Shape x_copy_after(x);
  assert(x_copy_before == x_copy_after);
  assert(x.is_strongly_reduced());
  assert(x.OK());
#endif
}

template <typename T>
void
Octagonal_Shape<T>
::non_redundant_matrix_entries(std::vector<Bit_Row>& nr_rows) const {
  // Private method: the caller has to ensure the following.
  assert(space_dim > 0 && !marked_empty() && marked_strongly_closed());
  assert(nr_rows.empty());

  // Initialize `non_redundant' as if it was an OR_Matrix of booleans
  // (initially set to false).
  nr_rows.resize(2*space_dim);

  // 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 strongly
  // closed, this happens if and only if matrix[i][j] == -matrix[ci][cj].
  std::vector<dimension_type> no_sing_leaders;
  dimension_type sing_leader = 0;
  bool exist_sing_class = false;
  std::vector<dimension_type> successor;
  compute_successors(successor);
  compute_leaders(successor, no_sing_leaders, exist_sing_class, sing_leader);
  const dimension_type num_no_sing_leaders = no_sing_leaders.size();

  // Step 2: flag redundant constraints in `redundancy'.
  // Go through non-singular leaders first.
  for (dimension_type li = 0; li < num_no_sing_leaders; ++li) {
    const dimension_type i = no_sing_leaders[li];
    const dimension_type ci = coherent_index(i);
    typename OR_Matrix<N>::const_row_reference_type
      m_i = *(matrix.row_begin()+i);
    if (i % 2 == 0) {
      // Each positive equivalence class must have a single 0-cycle
      // connecting all equivalent variables in increasing order.
      // Note: by coherence assumption, the variables in the
      // corresponding negative equivalence class are
      // automatically connected.
      if (i != successor[i]) {
        dimension_type j = i;
        dimension_type next_j = successor[j];
        while (j != next_j) {
          nr_rows[next_j].set(j);
          j = next_j;
          next_j = successor[j];
        }
        const dimension_type cj = coherent_index(j);
        nr_rows[cj].set(ci);
      }
    }

    dimension_type rs_li = (li % 2 != 0) ? li :li+1;
    // Check if the constraint is redundant.
    PPL_DIRTY_TEMP(N, tmp);
    for (dimension_type lj = 0 ; lj <= rs_li; ++lj) {
      const dimension_type j = no_sing_leaders[lj];
      const dimension_type cj = coherent_index(j);
      const N& m_i_j = m_i[j];
      const N& m_i_ci = m_i[ci];
      bool to_add = true;
      // Control if the constraint is redundant by strong-coherence,
      // that is:
      // m_i_j >= (m_i_ci + m_cj_j)/2,   where j != ci.
      if (j != ci) {
        add_assign_r(tmp, m_i_ci, matrix[cj][j], ROUND_UP);
        div2exp_assign_r(tmp, tmp, 1, ROUND_UP);
        if (m_i_j >= tmp)
          // The constraint is redundant.
          continue;
      }
      // Control if the constraint is redundant by strong closure, that is
      // if there is a path from i to j (i = i_0, ... , i_n = j), such that
      // m_i_j = sum_{k=0}^{n-1} m_{i_k}_{i_(k+1)}.
      // Since the octagon is already strongly closed, the above relation
      // is reduced to three case, in accordance with k, i, j inter-depend:
      // exit k such that
      // 1.) m_i_j >= m_i_k   + m_cj_ck,   if k < j < i; or
      // 2.) m_i_j >= m_i_k   + m_k,_j,    if j < k < i; or
      // 3.) m_i_j >= m_ck_ci + m_k_j,     if j < i < k.
      // Note: `i > j'.
      for (dimension_type lk = 0; lk < num_no_sing_leaders; ++lk) {
        const dimension_type k = no_sing_leaders[lk];
        if (k != i && k != j) {
          dimension_type ck = coherent_index(k);
          if (k < j)
            // Case 1.
            add_assign_r(tmp, m_i[k], matrix[cj][ck], ROUND_UP);
          else if (k < i)
            // Case 2.
            add_assign_r(tmp, m_i[k], matrix[k][j], ROUND_UP);
          else
            // Case 3.
            add_assign_r(tmp, matrix[ck][ci], matrix[k][j], ROUND_UP);

          // Checks if the constraint is redundant.
          if (m_i_j >= tmp) {
            to_add = false;
            break;
          }
        }
      }

      if (to_add)
        // The constraint is not redundant.
        nr_rows[i].set(j);
    }
  }

  // If there exist a singular equivalence class, then it must have a
  // single 0-cycle connecting all the positive and negative equivalent
  // variables.
  // Note: the singular class is not connected with the other classes.
  if (exist_sing_class) {
    nr_rows[sing_leader].set(sing_leader+1);
    if (successor[sing_leader+1] != sing_leader+1) {
      dimension_type j = sing_leader;
      dimension_type next_jj = successor[j+1];
      while (next_jj != j+1) {
        nr_rows[next_jj].set(j);
        j = next_jj;
        next_jj = successor[j+1];
      }
      nr_rows[j+1].set(j);
    }
    else
      nr_rows[sing_leader+1].set(sing_leader);
  }
}

template <typename T>
void
Octagonal_Shape<T>::upper_bound_assign(const Octagonal_Shape& y) {
  // Dimension-compatibility check.
  if (space_dim != y.space_dim)
    throw_dimension_incompatible("upper_bound_assign(y)", y);

  // The hull of an octagon `x' with an empty octagon is `x'.
  y.strong_closure_assign();
  if (y.marked_empty())
    return;
  strong_closure_assign();
  if (marked_empty()) {
    *this = y;
    return;
  }

  // The oct-hull is obtained by computing maxima.
  typename OR_Matrix<N>::const_element_iterator j = y.matrix.element_begin();
  for (typename OR_Matrix<N>::element_iterator i = matrix.element_begin(),
         matrix_element_end = matrix.element_end();
       i != matrix_element_end; ++i, ++j)
    max_assign(*i, *j);

  // The result is still closed.
  assert(OK());
}

template <typename T>
void
Octagonal_Shape<T>::difference_assign(const Octagonal_Shape& y) {
  // Dimension-compatibility check.
  if (space_dim != y.space_dim)
    throw_dimension_incompatible("difference_assign(y)", y);

  Octagonal_Shape& x = *this;

  // Being lazy here is only harmful.
  // We close.
  x.strong_closure_assign();
  // The difference of an empty octagon and of an octagon `p' is empty.
  if (x.marked_empty())
    return;
  // The difference of a octagon `p' and an empty octagon is `p'.
  if (y.marked_empty())
    return;

  // If both octagons are zero-dimensional,
  // then at this point they are necessarily universe octagons,
  // so that their difference is empty.
  if (x.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;
  }

  Octagonal_Shape new_oct(space_dim, EMPTY);
  // We take a constraint of the octagon y at the time and we
  // consider its complementary. Then we intersect the union
  // of these complementaries with the octagon 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 octagon `x' is included the octagon defined by `c',
    // then `c' _must_ be skipped, as adding its complement to `x'
    // would result in the empty octagon, and as we would obtain
    // a result that is less precise than the difference.
    if (x.relation_with(c).implies(Poly_Con_Relation::is_included()))
      continue;
    Octagonal_Shape z = x;
    const Linear_Expression e = Linear_Expression(c);
    z.add_constraint(e <= 0);
    if (!z.is_empty())
      new_oct.upper_bound_assign(z);
    if (c.is_equality()) {
      z = x;
      z.add_constraint(e >= 0);
      if (!z.is_empty())
        new_oct.upper_bound_assign(z);
    }
  }
  *this = new_oct;
  assert(OK());
}

template <typename T>
bool
Octagonal_Shape<T>::simplify_using_context_assign(const Octagonal_Shape& y) {
  Octagonal_Shape& x = *this;
  const dimension_type dim = x.space_dimension();
  // Dimension-compatibility check.
  if (dim != y.space_dimension())
    throw_dimension_incompatible("simplify_using_context_assign(y)", y);

  // Filter away the zero-dimensional case.
  if (dim == 0) {
    if (y.marked_empty()) {
      x.set_zero_dim_univ();
      return false;
    }
    else
      return !x.marked_empty();
  }

  // Filter away the case where `x' contains `y'
  // (this subsumes the case when `y' is empty).
  if (x.contains(y)) {
    Octagonal_Shape<T> res(dim, UNIVERSE);
    x.swap(res);
    return false;
  }

  typedef typename OR_Matrix<N>::row_iterator Row_Iter;
  typedef typename OR_Matrix<N>::const_row_iterator Row_CIter;
  typedef typename OR_Matrix<N>::element_iterator Elem_Iter;
  typedef typename OR_Matrix<N>::const_element_iterator Elem_CIter;

  // Filter away the case where `x' is empty.
  x.strong_closure_assign();
  if (x.marked_empty()) {
    // Search for a constraint of `y' that is not a tautology.
    dimension_type i;
    dimension_type j;
    // Prefer unary constraints.
    for (i = 0; i < 2*dim; i += 2) {
      // FIXME: if N is a float or bounded integer type, then
      // we also need to check that we are actually able to construct
      // a constraint inconsistent wrt this one.
      // Use something like !is_maximal()?
      if (!is_plus_infinity(y.matrix_at(i, i+1))) {
        j = i+1;
        goto found;
      }
      // Use something like !is_maximal()?
      if (!is_plus_infinity(y.matrix_at(i+1, i))) {
        j = i;
        ++i;
        goto found;
      }
    }
    // Then search binary constraints.
    // TODO: use better iteration scheme.
    for (i = 2; i < 2*dim; ++i)
      for (j = 0; j < i; ++j) {
        // Use something like !is_maximal()?
        if (!is_plus_infinity(y.matrix_at(i, j)))
          goto found;
      }

    // Not found: we were not able to build a constraint contradicting
    // one of the constraints in `y': `x' cannot be enlarged.
    return false;

  found:
    // Found: build a new OS contradicting the constraint found.
    assert(i < dim && j < dim && i != j);
    Octagonal_Shape<T> res(dim, UNIVERSE);
    // FIXME: compute a proper contradicting constraint.
    PPL_DIRTY_TEMP(N, tmp);
    assign_r(tmp, 1, ROUND_UP);
    add_assign_r(tmp, tmp, y.matrix_at(i, j), ROUND_UP);
    // CHECKME: round down is really meant.
    neg_assign_r(res.matrix_at(j, i), tmp, ROUND_DOWN);
    assert(!is_plus_infinity(res.matrix_at(j, i)));
    x.swap(res);
    return false;
  }

  // Here `x' and `y' are not empty and strongly closed;
  // also, `x' does not contain `y'.
  // Let `target' be the intersection of `x' and `y'.
  Octagonal_Shape<T> target = x;
  target.intersection_assign(y);
  const bool bool_result = !target.is_empty();

  // Compute redundancy information for x and ...
  // TODO: provide a nicer data structure for redundancy.
  std::vector<Bit_Row> x_nonred;
  x.non_redundant_matrix_entries(x_nonred);
  // ... count the non-redundant constraints.
  dimension_type x_num_nonred = 0;
  for (size_t i = x_nonred.size(); i-- > 0 ; )
    x_num_nonred += x_nonred[i].count_ones();
  assert(x_num_nonred > 0);

  // Let `yy' be a copy of `y': we will keep adding to `yy'
  // the non-redundant constraints of `x',
  // stopping as soon as `yy' becomes equal to `target'.
  Octagonal_Shape<T> yy = y;

  // The constraints added to `yy' will be recorded in `res' ...
  Octagonal_Shape<T> res(dim, UNIVERSE);
  // ... and we will count them too.
  dimension_type res_num_nonred = 0;

  // Compute leader information for `x'.
  std::vector<dimension_type> x_leaders;
  x.compute_leaders(x_leaders);

  // First go through the unary equality constraints.
  // Find the leader of the singular equivalence class (it is even!).
  dimension_type sing_leader;
  for (sing_leader = 0; sing_leader < 2*dim; sing_leader += 2) {
    if (sing_leader == x_leaders[sing_leader]) {
      const N& x_s_ss = x.matrix_at(sing_leader, sing_leader+1);
      const N& x_ss_s = x.matrix_at(sing_leader+1, sing_leader);
      if (is_additive_inverse(x_s_ss, x_ss_s))
        // Singular leader found.
        break;
    }
  }

  // Unary equalities have `sing_leader' as a leader.
  for (dimension_type i = sing_leader; i < 2*dim; i += 2) {
    if (x_leaders[i] != sing_leader)
      continue;
    // Found a unary equality constraint:
    // see if any of the two inequalities have to be added.
    const N& x_i_ii = x.matrix_at(i, i+1);
    N& yy_i_ii = yy.matrix_at(i, i+1);
    if (x_i_ii < yy_i_ii) {
      // The \leq inequality is not implied by context.
      res.matrix_at(i, i+1) = x_i_ii;
      ++res_num_nonred;
      // Tighten context `yy' using the newly added constraint.
      yy_i_ii = x_i_ii;
      yy.reset_strongly_closed();
    }
    const N& x_ii_i = x.matrix_at(i+1, i);
    N& yy_ii_i = yy.matrix_at(i+1, i);
    if (x_ii_i < yy_ii_i) {
      // The \geq inequality is not implied by context.
      res.matrix_at(i+1, i) = x_ii_i;
      ++res_num_nonred;
      // Tighten context `yy' using the newly added constraint.
      yy_ii_i = x_ii_i;
      yy.reset_strongly_closed();
    }
    // Restore strong closure, if it was lost.
    if (!yy.marked_strongly_closed()) {
      Variable var_i(i/2);
      yy.incremental_strong_closure_assign(var_i);
      if (target.contains(yy)) {
        // Target reached: swap `x' and `res' if needed.
        if (res_num_nonred < x_num_nonred) {
          res.reset_strongly_closed();
          x.swap(res);
        }
        return bool_result;
      }
    }
  }

  // Go through the binary equality constraints.
  for (dimension_type i = 0; i < 2*dim; ++i) {
    const dimension_type j = x_leaders[i];
    if (j == i || j == sing_leader)
      continue;
    const N& x_i_j = x.matrix_at(i, j);
    assert(!is_plus_infinity(x_i_j));
    N& yy_i_j = yy.matrix_at(i, j);
    if (x_i_j < yy_i_j) {
      res.matrix_at(i, j) = x_i_j;
      ++res_num_nonred;
      // Tighten context `yy' using the newly added constraint.
      yy_i_j = x_i_j;
      yy.reset_strongly_closed();
    }
    const N& x_j_i = x.matrix_at(j, i);
    N& yy_j_i = yy.matrix_at(j, i);
    assert(!is_plus_infinity(x_j_i));
    if (x_j_i < yy_j_i) {
      res.matrix_at(j, i) = x_j_i;
      ++res_num_nonred;
      // Tighten context `yy' using the newly added constraint.
      yy_j_i = x_j_i;
      yy.reset_strongly_closed();
    }
    // Restore strong closure, if it was lost.
    if (!yy.marked_strongly_closed()) {
      Variable var_j(j/2);
      yy.incremental_strong_closure_assign(var_j);
      if (target.contains(yy)) {
        // Target reached: swap `x' and `res' if needed.
        if (res_num_nonred < x_num_nonred) {
          res.reset_strongly_closed();
          x.swap(res);
        }
        return bool_result;
      }
    }
  }

  // Finally go through the (proper) inequality constraints:
  // both indices i and j should be leaders.
  // FIXME: improve iteration scheme (are we doing twice the work?)
  for (dimension_type i = 0; i < 2*dim; ++i) {
    if (i != x_leaders[i])
      continue;
    const Bit_Row& x_nonred_i = x_nonred[i];
    for (dimension_type j = 0; j < 2*dim; ++j) {
      if (j != x_leaders[j])
        continue;
      if (i >= j) {
        if (!x_nonred_i[j])
          continue;
      }
      else if (!x_nonred[j][i])
        continue;
      N& yy_i_j = yy.matrix_at(i, j);
      const N& x_i_j = x.matrix_at(i, j);
      if (x_i_j < yy_i_j) {
        res.matrix_at(i, j) = x_i_j;
        ++res_num_nonred;
        // Tighten context `yy' using the newly added constraint.
        yy_i_j = x_i_j;
        yy.reset_strongly_closed();
        Variable var(i/2);
        yy.incremental_strong_closure_assign(var);
        if (target.contains(yy)) {
          // Target reached: swap `x' and `res' if needed.
          if (res_num_nonred < x_num_nonred) {
            res.reset_strongly_closed();
            x.swap(res);
          }
          return bool_result;
        }
      }
    }
  }
  // This point should be unreachable.
  throw std::runtime_error("PPL internal error");
}

template <typename T>
void
Octagonal_Shape<T>::add_space_dimensions_and_embed(dimension_type m) {
  // Adding no dimensions is a no-op.
  if (m == 0)
    return;

  const dimension_type new_dim = space_dim + m;
  const bool was_zero_dim_univ = !marked_empty() && space_dim == 0;

  // To embed an n-dimension space octagon in a (n+m)-dimension space,
  // we just add `m' variables in the matrix of constraints.
  matrix.grow(new_dim);
  space_dim = new_dim;
  // If `*this' was the zero-dim space universe octagon,
  // then we can set the strongly closure flag.
  if (was_zero_dim_univ)
    set_strongly_closed();

  assert(OK());
}

template <typename T>
void
Octagonal_Shape<T>::add_space_dimensions_and_project(dimension_type m) {
  // Adding no dimensions is a no-op.
  if (m == 0)
    return;

  const dimension_type n = matrix.num_rows();

  // To project an n-dimension space OS in a (space_dim+m)-dimension space,
  // we just add `m' columns and rows in the matrix of constraints.
  add_space_dimensions_and_embed(m);
  // We insert 0 where it needs.
  // Attention: now num_rows of matrix is update!
  for (typename OR_Matrix<N>::row_iterator i = matrix.row_begin() + n,
         matrix_row_end =  matrix.row_end(); i != matrix_row_end; i += 2) {
    typename OR_Matrix<N>::row_reference_type x_i = *i;
    typename OR_Matrix<N>::row_reference_type x_ci = *(i+1);
    const dimension_type ind = i.index();
    assign_r(x_i[ind+1], 0, ROUND_NOT_NEEDED);
    assign_r(x_ci[ind], 0, ROUND_NOT_NEEDED);
  }

  if (marked_strongly_closed())
    reset_strongly_closed();
  assert(OK());
}

template <typename T>
void
Octagonal_Shape<T>
::remove_space_dimensions(const Variables_Set& to_be_removed) {
  // The removal of no dimensions from any octagon is a no-op.
  // Note that this case also captures the only legal removal of
  // dimensions from a octagon in a 0-dim space.
  if (to_be_removed.empty()) {
    assert(OK());
    return;
  }

  // Dimension-compatibility check.
  const dimension_type min_space_dim = to_be_removed.space_dimension();
  if (space_dim < min_space_dim)
    throw_dimension_incompatible("remove_space_dimensions(vs)", min_space_dim);

  const dimension_type new_space_dim = space_dim - to_be_removed.size();

  strong_closure_assign();
  // When removing _all_ dimensions from an octagon,
  // we obtain the zero-dimensional octagon.
  if (new_space_dim == 0) {
    matrix.shrink(0);
    if (!marked_empty())
      // We set the zero_dim_univ flag.
      set_zero_dim_univ();
    space_dim = 0;
    assert(OK());
    return;
  }

  // We consider every variable and we check if it is to be removed.
  // If it is to be removed, we pass to the successive one, elsewhere
  // we move its elements in the right position.
  Variables_Set::const_iterator tbr = to_be_removed.begin();
  dimension_type ftr = *tbr;
  dimension_type ftr_size = 2*ftr*(ftr+1);
  typename OR_Matrix<N>::element_iterator
    iter = matrix.element_begin()+ftr_size;

  dimension_type i = ftr + 1;
  while (i < space_dim) {
    if (to_be_removed.count(i) != 0)
      ++i;
    else {
      typename OR_Matrix<N>::row_iterator
        row_iter = matrix.row_begin()+2*i;
      typename OR_Matrix<N>::row_reference_type
        row_ref = *row_iter;
      typename OR_Matrix<N>::row_reference_type
        row_ref1 = *(++row_iter);
      // If variable(j) is to remove, we pass another variable,
      // else we shift its cells to up right.
      // Attention: first we shift the cells corrispondent to the first
      // row of variable(j), then we shift the cells corrispondent to the
      // second row. We recall that every variable is represented
      // in the `matrix' by two rows and two rows.
      for (dimension_type j = 0; j <= i; ++j)
        if (to_be_removed.count(j) == 0) {
          assign_or_swap(*(iter++), row_ref[2*j]);
          assign_or_swap(*(iter++), row_ref[2*j+1]);
        }
      for (dimension_type j = 0; j <= i; ++j)
        if (to_be_removed.count(j) == 0) {
          assign_or_swap(*(iter++), row_ref1[2*j]);
          assign_or_swap(*(iter++), row_ref1[2*j+1]);
        }
      ++i;
    }
  }
  // Update the space dimension.
  matrix.shrink(new_space_dim);
  space_dim = new_space_dim;
  assert(OK());
}

template <typename T>
template <typename Partial_Function>
void
Octagonal_Shape<T>::map_space_dimensions(const Partial_Function& pfunc) {
  if (space_dim == 0)
    return;

  if (pfunc.has_empty_codomain()) {
    // All dimensions vanish: the octagon becomes zero_dimensional.
    remove_higher_space_dimensions(0);
    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)
    strong_closure_assign();

  // If the octagon is empty, then it is sufficient to adjust
  // the space dimension of the octagon.
  if (marked_empty()) {
    remove_higher_space_dimensions(new_space_dim);
    return;
  }

  // We create a new matrix with the new space dimension.
  OR_Matrix<N> x(new_space_dim);

  typedef typename OR_Matrix<N>::row_iterator Row_Iterator;
  typedef typename OR_Matrix<N>::row_reference_type Row_Reference;

  Row_Iterator m_begin = x.row_begin();

  for (Row_Iterator i_iter = matrix.row_begin(), i_end = matrix.row_end();
       i_iter != i_end; i_iter += 2) {
    dimension_type new_i;
    dimension_type i = i_iter.index()/2;
    // We copy and place in the position into `x' the only cells of
    // the `matrix' that refer to both mapped variables,
    // the variable `i' and `j'.
    if (pfunc.maps(i, new_i)) {
      Row_Reference r_i = *i_iter;
      Row_Reference r_ii = *(i_iter + 1);
      dimension_type double_new_i = 2*new_i;
      Row_Iterator x_iter = m_begin + double_new_i;
      Row_Reference x_i = *x_iter;
      Row_Reference x_ii = *(x_iter + 1);
      for (dimension_type j = 0; j <= i; ++j) {
        dimension_type new_j;
        // If also the second variable is mapped, we work.
        if (pfunc.maps(j, new_j)) {
          dimension_type dj = 2*j;
          dimension_type double_new_j = 2*new_j;
          // Mapped the constraints, exchanging the indexes.
          // Attention: our matrix is pseudo-triangular.
          // If new_j > new_i, we must consider, as rows, the rows of
          // the variable new_j, and not of new_i ones.
          if (new_i >= new_j) {
            assign_or_swap(x_i[double_new_j], r_i[dj]);
            assign_or_swap(x_ii[double_new_j], r_ii[dj]);
            assign_or_swap(x_ii[double_new_j+1], r_ii[dj + 1]);
            assign_or_swap(x_i[double_new_j+1], r_i[dj + 1]);
          }
          else {
            Row_Iterator xj_iter = m_begin + double_new_j;
            Row_Reference x_j = *xj_iter;
            Row_Reference x_jj = *(xj_iter + 1);
            assign_or_swap(x_jj[double_new_i+1], r_i[dj]);
            assign_or_swap(x_jj[double_new_i], r_ii[dj]);
            assign_or_swap(x_j[double_new_i+1], r_i[dj+1]);
            assign_or_swap(x_j[double_new_i], r_ii[dj+1]);
          }

        }
      }
    }
  }

  std::swap(matrix, x);
  space_dim = new_space_dim;
  assert(OK());
}

template <typename T>
void
Octagonal_Shape<T>::intersection_assign(const Octagonal_Shape& y) {
  // Dimension-compatibility check.
  if (space_dim != y.space_dim)
    throw_dimension_incompatible("intersection_assign(y)", y);

  // If one of the two octagons is empty, the intersection is empty.
  if (marked_empty())
    return;
  if (y.marked_empty()) {
    set_empty();
    return;
  }
  // If both octagons 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 octagons we compare the constraints
  // and we choose the less values.
  bool changed = false;

  typename OR_Matrix<N>::const_element_iterator j = y.matrix.element_begin();
  for (typename OR_Matrix<N>::element_iterator i = matrix.element_begin(),
         matrix_element_end = matrix.element_end();
       i != matrix_element_end;
       ++i, ++j) {
    N& elem = *i;
    const N& y_elem = *j;
    if (y_elem < elem) {
      elem = y_elem;
      changed = true;
    }
  }

  // This method not preserve the closure.
  if (changed && marked_strongly_closed())
    reset_strongly_closed();
  assert(OK());
}

template <typename T>
template <typename Iterator>
void
Octagonal_Shape<T>::CC76_extrapolation_assign(const Octagonal_Shape& y,
                                              Iterator first, Iterator last,
                                              unsigned* tp) {
  // Dimension-compatibility check.
  if (space_dim != y.space_dim)
    throw_dimension_incompatible("CC76_extrapolation_assign(y)", y);

#ifndef NDEBUG
  {
    // We assume that `y' is contained in or equal to `*this'.
    const Octagonal_Shape x_copy = *this;
    const Octagonal_Shape y_copy = y;
    assert(x_copy.contains(y_copy));
  }
#endif

  // If both octagons are zero-dimensional,
  // since `*this' contains `y', we simply return `*this'.
  if (space_dim == 0)
    return;

  strong_closure_assign();
  // If `*this' is empty, since `*this' contains `y', `y' is empty too.
  if (marked_empty())
    return;
  y.strong_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) {
    Octagonal_Shape 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.
  typename OR_Matrix<N>::const_element_iterator j = y.matrix.element_begin();
  for (typename OR_Matrix<N>::element_iterator i = matrix.element_begin(),
         matrix_element_end = matrix.element_end();
       i != matrix_element_end;
       ++i, ++j) {
    const N& y_elem = *j;
    N& elem = *i;
    if (y_elem < elem) {
      Iterator k = std::lower_bound(first, last, elem);
      if (k != last) {
        if (elem < *k)
          assign_r(elem, *k, ROUND_UP);
      }
      else
        assign_r(elem, PLUS_INFINITY, ROUND_NOT_NEEDED);
    }
  }

  reset_strongly_closed();
  assert(OK());
}

template <typename T>
void
Octagonal_Shape<T>
::get_limiting_octagon(const Constraint_System& cs,
                       Octagonal_Shape& limiting_octagon) const {
  const dimension_type cs_space_dim = cs.space_dimension();
  // Private method: the caller has to ensure the following.
  assert(cs_space_dim <= space_dim);

  strong_closure_assign();
  bool is_oct_changed = false;

  // Allocate temporaries outside of the loop.
  PPL_DIRTY_TEMP_COEFFICIENT(coeff);
  PPL_DIRTY_TEMP_COEFFICIENT(term);
  PPL_DIRTY_TEMP(N, d);

  for (Constraint_System::const_iterator cs_i = cs.begin(),
         cs_end = cs.end(); cs_i != cs_end; ++cs_i) {
    const Constraint& c = *cs_i;
    dimension_type num_vars = 0;
    dimension_type i = 0;
    dimension_type j = 0;
    // Constraints that are not octagonal differences are ignored.
    if (!extract_octagonal_difference(c, cs_space_dim, num_vars, i, j,
                                      coeff, term))
      continue;

    typedef typename OR_Matrix<N>::const_row_iterator Row_iterator;
    typedef typename OR_Matrix<N>::const_row_reference_type Row_reference;
    typedef typename OR_Matrix<N>::row_iterator Row_Iterator;
    typedef typename OR_Matrix<N>::row_reference_type Row_Reference;
    Row_iterator m_begin = matrix.row_begin();
    // Select the cell to be modified for the "<=" part of the constraint.
    Row_iterator i_iter = m_begin + i;
    Row_reference m_i = *i_iter;
    OR_Matrix<N>& lo_mat = limiting_octagon.matrix;
    Row_Iterator lo_iter = lo_mat.row_begin() + i;
    Row_Reference lo_m_i = *lo_iter;
    N& lo_m_i_j = lo_m_i[j];
    if (coeff < 0)
      neg_assign(coeff);
    // Compute the bound for `m_i_j', rounding towards plus infinity.
    div_round_up(d, term, coeff);
    if (m_i[j] <= d)
      if (c.is_inequality()) {
        if (lo_m_i_j > d) {
          lo_m_i_j = d;
          is_oct_changed = true;
        }
        else {
          // Select the right row of the cell.
          if (i % 2 == 0) {
            ++i_iter;
            ++lo_iter;
          }
          else {
            --i_iter;
            --lo_iter;
          }
          Row_reference m_ci = *i_iter;
          Row_Reference lo_m_ci = *lo_iter;
          // Select the right column of the cell.
          dimension_type cj = coherent_index(j);
          N& lo_m_ci_cj = lo_m_ci[cj];
          neg_assign(term);
          div_round_up(d, term, coeff);
          if (m_ci[cj] <= d && lo_m_ci_cj > d) {
            lo_m_ci_cj = d;
            is_oct_changed = true;
          }
        }
      }
  }
  // In general, adding a constraint does not preserve the strongly
  // closure of the octagon.
  if (is_oct_changed && limiting_octagon.marked_strongly_closed())
    limiting_octagon.reset_strongly_closed();
}

template <typename T>
void
Octagonal_Shape<T>
::limited_CC76_extrapolation_assign(const Octagonal_Shape& y,
                                    const Constraint_System& cs,
                                    unsigned* tp) {

  // Dimension-compatibility check.
  if (space_dim != y.space_dim)
    throw_dimension_incompatible("limited_CC76_extrapolation_assign(y, cs)",
                                 y);
  // `cs' must be dimension-compatible with the two octagons.
  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 octagons in a
  // zero-dimensional space is a octagon 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 Octagonal_Shape x_copy = *this;
    const Octagonal_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;

  Octagonal_Shape limiting_octagon(space_dim, UNIVERSE);
  get_limiting_octagon(cs, limiting_octagon);
  CC76_extrapolation_assign(y, tp);
  intersection_assign(limiting_octagon);
}

template <typename T>
void
Octagonal_Shape<T>::BHMZ05_widening_assign(const Octagonal_Shape& y,
                                           unsigned* tp) {
  // Dimension-compatibility check.
  if (space_dim != y.space_dim)
    throw_dimension_incompatible("BHMZ05_widening_assign(y)", y);

#ifndef NDEBUG
  {
    // We assume that `y' is contained in or equal to `*this'.
    const Octagonal_Shape x_copy = *this;
    const Octagonal_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) {
    Octagonal_Shape 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_strongly_closed() && y.marked_strongly_closed());
  // Minimize `y'.
  y.strong_reduction_assign();

  // Extrapolate unstable bounds.
  typename OR_Matrix<N>::const_element_iterator j = y.matrix.element_begin();
  for (typename OR_Matrix<N>::element_iterator i = matrix.element_begin(),
       matrix_element_end = matrix.element_end();
       i != matrix_element_end;
       ++i, ++j) {
    N& elem = *i;
      // Note: in the following line the use of `!=' (as opposed to
      // the use of `<' that would seem -but is not- equivalent) is
      // intentional.
    if (*j != elem)
      assign_r(elem, PLUS_INFINITY, ROUND_NOT_NEEDED);
  }
  reset_strongly_closed();
  assert(OK());
}

template <typename T>
void
Octagonal_Shape<T>
::limited_BHMZ05_extrapolation_assign(const Octagonal_Shape& y,
                                      const Constraint_System& cs,
                                      unsigned* tp) {

  // Dimension-compatibility check.
  if (space_dim != y.space_dim)
    throw_dimension_incompatible("limited_BHMZ05_extrapolation_assign(y, cs)",
                                 y);
  // `cs' must be dimension-compatible with the two octagons.
  const dimension_type cs_space_dim = cs.space_dimension();
  if (space_dim < cs_space_dim)
    throw_constraint_incompatible("limited_CH78_extrapolation_assign(y, cs)");

  // Strict inequalities not allowed.
  if (cs.has_strict_inequalities())
    throw_constraint_incompatible("limited_CH78_extrapolation_assign(y, cs)");

  // The limited BHMZ05-extrapolation between two octagons in a
  // zero-dimensional space is a octagon 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 Octagonal_Shape x_copy = *this;
    const Octagonal_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;

  Octagonal_Shape limiting_octagon(space_dim, UNIVERSE);
  get_limiting_octagon(cs, limiting_octagon);
  BHMZ05_widening_assign(y, tp);
  intersection_assign(limiting_octagon);
}

template <typename T>
void
Octagonal_Shape<T>::CC76_narrowing_assign(const Octagonal_Shape& y) {
  // Dimension-compatibility check.
  if (space_dim != y.space_dim)
    throw_dimension_incompatible("CC76_narrowing_assign(y)", y);

#ifndef NDEBUG
  {
    // We assume that `*this' is contained in or equal to `y'.
    const Octagonal_Shape x_copy = *this;
    const Octagonal_Shape y_copy = y;
    assert(y_copy.contains(x_copy));
  }
#endif

  // If both octagons are zero-dimensional, since `*this' contains `y',
  // we simply return '*this'.
  if (space_dim == 0)
    return;

  y.strong_closure_assign();
  // If `y' is empty, since `y' contains `*this', `*this' is empty too.
  if (y.marked_empty())
    return;
  strong_closure_assign();
  // If `*this' is empty, we return.
  if (marked_empty())
    return;

  // We consider a constraint of `*this', if its value is `plus_infinity',
  // we take the value of the corresponding constraint of `y'.
  bool is_oct_changed = false;
  typename OR_Matrix<N>::const_element_iterator j = y.matrix.element_begin();
  for (typename OR_Matrix<N>::element_iterator i = matrix.element_begin(),
       matrix_element_end = matrix.element_end();
       i != matrix_element_end;
       ++i, ++j) {
     if (!is_plus_infinity(*i)
         && !is_plus_infinity(*j)
         && *i != *j) {
      *i = *j;
      is_oct_changed = true;
    }
  }

  if (is_oct_changed && marked_strongly_closed())
    reset_strongly_closed();
  assert(OK());
}

template <typename T>
void
Octagonal_Shape<T>
::deduce_v_pm_u_bounds(const dimension_type v_id,
                       const dimension_type last_id,
                       const Linear_Expression& sc_expr,
                       Coefficient_traits::const_reference sc_den,
                       const N& ub_v) {
  // Private method: the caller has to ensure the following.
  assert(sc_den > 0);
  assert(!is_plus_infinity(ub_v));

  PPL_DIRTY_TEMP0(mpq_class, mpq_sc_den);
  assign_r(mpq_sc_den, sc_den, ROUND_NOT_NEEDED);

  // No need to consider indices greater than `last_id'.
  const dimension_type n_v = 2*v_id;
  typename OR_Matrix<N>::row_reference_type m_cv = matrix[n_v+1];

  // Speculatively allocate temporaries out of the loop.
  PPL_DIRTY_TEMP(N, half);
  PPL_DIRTY_TEMP0(mpq_class, minus_lb_u);
  PPL_DIRTY_TEMP0(mpq_class, q);
  PPL_DIRTY_TEMP0(mpq_class, minus_q);
  PPL_DIRTY_TEMP0(mpq_class, ub_u);
  PPL_DIRTY_TEMP0(mpq_class, lb_u);
  PPL_DIRTY_TEMP(N, up_approx);
  PPL_DIRTY_TEMP_COEFFICIENT(minus_expr_u);

  for (dimension_type u_id = last_id+1; u_id-- > 0; ) {
    // Skip the case when `u_id == v_id'.
    if (u_id == v_id)
      continue;
    const Coefficient& expr_u = sc_expr.coefficient(Variable(u_id));
    // Skip the case when `expr_u == 0'.
    if (expr_u == 0)
      continue;

    const dimension_type n_u = u_id*2;
    // If `expr_u' is positive, we can improve `v - u'.
    if (expr_u > 0) {
      if (expr_u >= sc_den) {
        // Here q >= 1: deducing `v - u <= ub_v - ub_u'.
        // We avoid to check if `ub_u' is plus infinity, because
        // it is used for the computation of `ub_v'.
        // Let half = m_cu_u / 2.
        div2exp_assign_r(half, matrix[n_u+1][n_u], 1, ROUND_UP);
        N& m_v_minus_u = (n_v < n_u) ? matrix[n_u][n_v] : m_cv[n_u+1];
        sub_assign_r(m_v_minus_u, ub_v, half, ROUND_UP);
      }
      else {
        // Here 0 < q < 1.
        typename OR_Matrix<N>::row_reference_type m_u = matrix[n_u];
        const N& m_u_cu = m_u[n_u+1];
        if (!is_plus_infinity(m_u_cu)) {
          // Let `ub_u' and `lb_u' be the known upper and lower bound
          // for `u', respectively. The upper bound for `v - u' is
          // computed as `ub_v - (q * ub_u + (1-q) * lb_u)',
          // i.e., `ub_v + (-lb_u) - q * (ub_u + (-lb_u))'.
          assign_r(minus_lb_u, m_u_cu, ROUND_NOT_NEEDED);
          div2exp_assign_r(minus_lb_u, minus_lb_u, 1, ROUND_NOT_NEEDED);
          assign_r(q, expr_u, ROUND_NOT_NEEDED);
          div_assign_r(q, q, mpq_sc_den, ROUND_NOT_NEEDED);
          assign_r(ub_u, matrix[n_u+1][n_u], ROUND_NOT_NEEDED);
          div2exp_assign_r(ub_u, ub_u, 1, 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);
          assign_r(up_approx, minus_lb_u, ROUND_UP);
          // Deducing `v - u <= ub_v - (q * ub_u + (1-q) * lb_u)'.
          N& m_v_minus_u = (n_v < n_u) ? m_u[n_v] : m_cv[n_u+1];
          add_assign_r(m_v_minus_u, ub_v, up_approx, ROUND_UP);
        }
      }
    }
    else {
      assert(expr_u < 0);
      // If `expr_u' is negative, we can improve `v + u'.
      neg_assign(minus_expr_u, expr_u);
      if (minus_expr_u >= sc_den) {
        // Here q <= -1: Deducing `v + u <= ub_v + lb_u'.
        // We avoid to check if `lb_u' is plus infinity, because
        // it is used for the computation of `ub_v'.
        // Let half = m_u_cu / 2.
        div2exp_assign_r(half, matrix[n_u][n_u+1], 1, ROUND_UP);
        N& m_v_plus_u = (n_v < n_u) ? matrix[n_u+1][n_v] : m_cv[n_u];
        sub_assign_r(m_v_plus_u, ub_v, half, ROUND_UP);
      }
      else {
        // Here -1 < q < 0.
        typename OR_Matrix<N>::row_reference_type m_cu = matrix[n_u+1];
        const N& m_cu_u = m_cu[n_u];
        if (!is_plus_infinity(m_cu_u)) {
          // Let `ub_u' and `lb_u' be the known upper and lower bound
          // for `u', respectively. The upper bound for `v + u' is
          // computed as `ub_v + ((-q) * lb_u + (1+q) * ub_u)',
          // i.e., `ub_v + ub_u + (-q) * (lb_u - ub_u)'.
          assign_r(ub_u, m_cu[n_u], ROUND_NOT_NEEDED);
          div2exp_assign_r(ub_u, ub_u, 1, ROUND_NOT_NEEDED);
          assign_r(minus_q, minus_expr_u, ROUND_NOT_NEEDED);
          div_assign_r(minus_q, minus_q, mpq_sc_den, ROUND_NOT_NEEDED);
          assign_r(lb_u, matrix[n_u][n_u+1], ROUND_NOT_NEEDED);
          div2exp_assign_r(lb_u, lb_u, 1, ROUND_NOT_NEEDED);
          neg_assign_r(lb_u, lb_u, ROUND_NOT_NEEDED);
          // Compute `lb_u - ub_u'.
          sub_assign_r(lb_u, lb_u, ub_u, ROUND_NOT_NEEDED);
          // Compute `ub_u + (-q) * (lb_u - ub_u)'.
          add_mul_assign_r(ub_u, minus_q, lb_u, ROUND_NOT_NEEDED);
          assign_r(up_approx, ub_u, ROUND_UP);
          // Deducing `v + u <= ub_v + ((-q) * lb_u + (1+q) * ub_u)'.
          N& m_v_plus_u = (n_v < n_u) ? m_cu[n_v] : m_cv[n_u];
          add_assign_r(m_v_plus_u, ub_v, up_approx, ROUND_UP);
        }
      }
    }
  }
}

template <typename T>
void
Octagonal_Shape<T>
::deduce_minus_v_pm_u_bounds(const dimension_type v_id,
                             const dimension_type last_id,
                             const Linear_Expression& sc_expr,
                             Coefficient_traits::const_reference sc_den,
                             const N& minus_lb_v) {
  // Private method: the caller has to ensure the following.
  assert(sc_den > 0);
  assert(!is_plus_infinity(minus_lb_v));

  PPL_DIRTY_TEMP0(mpq_class, mpq_sc_den);
  assign_r(mpq_sc_den, sc_den, ROUND_NOT_NEEDED);

  // No need to consider indices greater than `last_id'.
  const dimension_type n_v = 2*v_id;
  typename OR_Matrix<N>::row_reference_type m_v = matrix[n_v];

  // Speculatively allocate temporaries out of the loop.
  PPL_DIRTY_TEMP(N, half);
  PPL_DIRTY_TEMP0(mpq_class, ub_u);
  PPL_DIRTY_TEMP0(mpq_class, q);
  PPL_DIRTY_TEMP0(mpq_class, minus_lb_u);
  PPL_DIRTY_TEMP(N, up_approx);
  PPL_DIRTY_TEMP_COEFFICIENT(minus_expr_u);

  for (dimension_type u_id = last_id+1; u_id-- > 0; ) {
    // Skip the case when `u_id == v_id'.
    if (u_id == v_id)
      continue;
    const Coefficient& expr_u = sc_expr.coefficient(Variable(u_id));
    // Skip the case when `expr_u == 0'.
    if (expr_u == 0)
      continue;

    const dimension_type n_u = u_id*2;
    // If `expr_u' is positive, we can improve `-v + u'.
    if (expr_u > 0) {
      if (expr_u >= sc_den) {
        // Here q >= 1: deducing `-v + u <= lb_u - lb_v',
        // i.e., `u - v <= (-lb_v) - (-lb_u)'.
        // We avoid to check if `lb_u' is plus infinity, because
        // it is used for the computation of `lb_v'.
        // Let half = m_u_cu / 2.
        div2exp_assign_r(half, matrix[n_u][n_u+1], 1, ROUND_UP);
        N& m_u_minus_v = (n_v < n_u) ? matrix[n_u+1][n_v+1] : m_v[n_u];
        sub_assign_r(m_u_minus_v, minus_lb_v, half, ROUND_UP);
      }
      else {
        // Here 0 < q < 1.
        typename OR_Matrix<N>::row_reference_type m_cu = matrix[n_u+1];
        const N& m_cu_u = m_cu[n_u];
        if (!is_plus_infinity(m_cu_u)) {
          // Let `ub_u' and `lb_u' be the known upper and lower bound
          // for `u', respectively. 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)) + minus_lb_v'.
          assign_r(ub_u, m_cu[n_u], ROUND_NOT_NEEDED);
          div2exp_assign_r(ub_u, ub_u, 1, ROUND_NOT_NEEDED);
          assign_r(q, expr_u, ROUND_NOT_NEEDED);
          div_assign_r(q, q, mpq_sc_den, ROUND_NOT_NEEDED);
          assign_r(minus_lb_u, matrix[n_u][n_u+1], ROUND_NOT_NEEDED);
          div2exp_assign_r(minus_lb_u, minus_lb_u, 1, ROUND_NOT_NEEDED);
          // Compute `ub_u - lb_u'.
          add_assign_r(minus_lb_u, ub_u, minus_lb_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);
          assign_r(up_approx, ub_u, ROUND_UP);
          // Deducing `u - v <= -lb_v - (q * lb_u + (1-q) * ub_u)'.
          N& m_u_minus_v = (n_v < n_u) ? m_cu[n_v+1] : m_v[n_u];
          add_assign_r(m_u_minus_v, minus_lb_v, up_approx, ROUND_UP);
        }
      }
    }
    else {
      assert(expr_u < 0);
      // If `expr_u' is negative, we can improve `-v - u'.
      neg_assign(minus_expr_u, expr_u);
      if (minus_expr_u >= sc_den) {
        // Here q <= -1: Deducing `-v - u <= -lb_v - ub_u'.
        // We avoid to check if `ub_u' is plus infinity, because
        // it is used for the computation of `lb_v'.
        // Let half = m_cu_u / 2.
        div2exp_assign_r(half, matrix[n_u+1][n_u], 1, ROUND_UP);
        N& m_minus_v_minus_u = (n_v < n_u) ? matrix[n_u][n_v+1] : m_v[n_u+1];
        sub_assign_r(m_minus_v_minus_u, minus_lb_v, half, ROUND_UP);
      }
      else {
        // Here -1 < q < 0.
        typename OR_Matrix<N>::row_reference_type m_u = matrix[n_u];
        const N& m_u_cu = m_u[n_u+1];
        if (!is_plus_infinity(m_u_cu)) {
          // Let `ub_u' and `lb_u' be the known upper and lower bound
          // for `u', respectively. The upper bound for `-v - u' is
          // computed as `-lb_v - ((-q)*ub_u + (1+q)*lb_u)',
          // i.e., `minus_lb_v - lb_u + q*(ub_u - lb_u)'.
          assign_r(ub_u, matrix[n_u+1][n_u], ROUND_NOT_NEEDED);
          div2exp_assign_r(ub_u, ub_u, 1, ROUND_NOT_NEEDED);
          assign_r(q, expr_u, ROUND_NOT_NEEDED);
          div_assign_r(q, q, mpq_sc_den, ROUND_NOT_NEEDED);
          assign_r(minus_lb_u, m_u[n_u+1], ROUND_NOT_NEEDED);
          div2exp_assign_r(minus_lb_u, minus_lb_u, 1, 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)'.
          add_mul_assign_r(minus_lb_u, q, ub_u, ROUND_NOT_NEEDED);
          assign_r(up_approx, minus_lb_u, ROUND_UP);
          // Deducing `-v - u <= -lb_v - ((-q) * ub_u + (1+q) * lb_u)'.
          N& m_minus_v_minus_u = (n_v < n_u) ? m_u[n_v+1] : m_v[n_u+1];
          add_assign_r(m_minus_v_minus_u, minus_lb_v, up_approx, ROUND_UP);
        }
      }
    }
  }
}

template <typename T>
void
Octagonal_Shape<T>
::forget_all_octagonal_constraints(const dimension_type v_id) {
  assert(v_id < space_dim);
  const dimension_type n_v = 2*v_id;
  typename OR_Matrix<N>::row_iterator m_iter = matrix.row_begin() + n_v;
  typename OR_Matrix<N>::row_reference_type r_v = *m_iter;
  typename OR_Matrix<N>::row_reference_type r_cv = *(++m_iter);
  for (dimension_type h = m_iter.row_size(); h-- > 0; ) {
    assign_r(r_v[h], PLUS_INFINITY, ROUND_NOT_NEEDED);
    assign_r(r_cv[h], PLUS_INFINITY, ROUND_NOT_NEEDED);
  }
  ++m_iter;
  for (typename OR_Matrix<N>::row_iterator m_end = matrix.row_end();
       m_iter != m_end; ++m_iter) {
    typename OR_Matrix<N>::row_reference_type r = *m_iter;
    assign_r(r[n_v], PLUS_INFINITY, ROUND_NOT_NEEDED);
    assign_r(r[n_v+1], PLUS_INFINITY, ROUND_NOT_NEEDED);
  }
}

template <typename T>
void
Octagonal_Shape<T>
::forget_binary_octagonal_constraints(const dimension_type v_id) {
  assert(v_id < space_dim);
  const dimension_type n_v = 2*v_id;
  typename OR_Matrix<N>::row_iterator m_iter = matrix.row_begin() + n_v;
  typename OR_Matrix<N>::row_reference_type r_v = *m_iter;
  typename OR_Matrix<N>::row_reference_type r_cv = *(++m_iter);
  for (dimension_type k = n_v; k-- > 0; ) {
    assign_r(r_v[k], PLUS_INFINITY, ROUND_NOT_NEEDED);
    assign_r(r_cv[k], PLUS_INFINITY, ROUND_NOT_NEEDED);
  }
  ++m_iter;
  for (typename OR_Matrix<N>::row_iterator m_end = matrix.row_end();
       m_iter != m_end; ++m_iter) {
    typename OR_Matrix<N>::row_reference_type r = *m_iter;
    assign_r(r[n_v], PLUS_INFINITY, ROUND_NOT_NEEDED);
    assign_r(r[n_v+1], PLUS_INFINITY, ROUND_NOT_NEEDED);
  }
}

template <typename T>
void
Octagonal_Shape<T>::unconstrain(const Variable var) {
  // Dimension-compatibility check.
  const dimension_type dim = var.id();
  if (space_dimension() < dim)
    throw_dimension_incompatible("unconstrain(var)", dim);

  // Enforce strong closure for precision.
  strong_closure_assign();

  // If the shape is empty, this is a no-op.
  if (marked_empty())
    return;

  forget_all_octagonal_constraints(dim);
  // Strong closure is preserved.
  assert(OK());
}

template <typename T>
void
Octagonal_Shape<T>::unconstrain(const Variables_Set& to_be_unconstrained) {
  // The cylindrification wrt no dimensions is a no-op.
  // This case captures the only legal cylindrification in a 0-dim space.
  if (to_be_unconstrained.empty())
    return;

  // Dimension-compatibility check.
  const dimension_type min_space_dim = to_be_unconstrained.space_dimension();
  if (space_dimension() < min_space_dim)
    throw_dimension_incompatible("unconstrain(vs)", min_space_dim);

  // Enforce strong closure for precision.
  strong_closure_assign();

  // If the shape is empty, this is a no-op.
  if (marked_empty())
    return;

  for (Variables_Set::const_iterator tbu = to_be_unconstrained.begin(),
         tbu_end = to_be_unconstrained.end(); tbu != tbu_end; ++tbu)
    forget_all_octagonal_constraints(*tbu);
  // Strong closure is preserved.
  assert(OK());
}

template <typename T>
void
Octagonal_Shape<T>::refine(const Variable var,
                           const Relation_Symbol relsym,
                           const Linear_Expression& expr,
                           Coefficient_traits::const_reference denominator) {
  assert(denominator != 0);
  const dimension_type expr_space_dim = expr.space_dimension();
  assert(space_dim >= expr_space_dim);
  const dimension_type var_id = var.id();
  assert(var_id <= space_dim);
  assert(expr.coefficient(var) == 0);
  assert(relsym != LESS_THAN && relsym != GREATER_THAN);

  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;

  // Variable index of the last non-zero coefficient in `expr', if any.
  dimension_type w_id = 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_id = i;
    }

  // 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.
  typedef typename OR_Matrix<N>::row_iterator Row_Iterator;
  typedef typename OR_Matrix<N>::row_reference_type Row_Reference;
  typedef typename OR_Matrix<N>::const_row_iterator Row_iterator;
  typedef typename OR_Matrix<N>::const_row_reference_type Row_reference;

  const Row_Iterator m_begin = matrix.row_begin();
  const dimension_type n_var = 2*var_id;
  PPL_DIRTY_TEMP_COEFFICIENT(minus_den);
  neg_assign(minus_den, denominator);

  // Since we are only able to record octagonal differences, we can
  // precisely deal with the case of a single variable only if its
  // coefficient (taking into account the denominator) is 1.
  // If this is not the case, we fall back to the general case
  // so as to over-approximate the constraint.
  if (t == 1 && expr.coefficient(Variable(w_id)) != denominator
      && expr.coefficient(Variable(w_id)) != minus_den)
    t = 2;

  if (t == 0) {
    // Case 1: expr == b.
    PPL_DIRTY_TEMP_COEFFICIENT(two_b);
    two_b = 2*b;
    switch (relsym) {
    case EQUAL:
      // Add the constraint `var == b/denominator'.
      add_octagonal_constraint(n_var+1, n_var, two_b, denominator);
      add_octagonal_constraint(n_var, n_var+1, two_b, minus_den);
      break;
    case LESS_OR_EQUAL:
      // Add the constraint `var <= b/denominator'.
      add_octagonal_constraint(n_var+1, n_var, two_b, denominator);
      break;
    case GREATER_OR_EQUAL:
      // Add the constraint `var >= b/denominator',
      // i.e., `-var <= -b/denominator',
      add_octagonal_constraint(n_var, n_var+1, two_b, minus_den);
      break;
    default:
      // We already dealt with the other cases.
      throw std::runtime_error("PPL internal error");
    }
  }
  else if (t == 1) {
    // Value of the one and only non-zero coefficient in `expr'.
    const Coefficient& w_coeff = expr.coefficient(Variable(w_id));
    const dimension_type n_w = 2*w_id;
    switch (relsym) {
    case EQUAL:
      if (w_coeff == denominator)
        // Add the new constraint `var - w = b/denominator'.
        if (var_id < w_id) {
          add_octagonal_constraint(n_w, n_var, b, denominator);
          add_octagonal_constraint(n_w+1, n_var+1, b, minus_den);
        }
        else {
          add_octagonal_constraint(n_var+1, n_w+1, b, denominator);
          add_octagonal_constraint(n_var, n_w, b, minus_den);
        }
      else
        // Add the new constraint `var + w = b/denominator'.
        if (var_id < w_id) {
          add_octagonal_constraint(n_w+1, n_var, b, denominator);
          add_octagonal_constraint(n_w, n_var+1, b, minus_den);
        }
        else {
          add_octagonal_constraint(n_var+1, n_w, b, denominator);
          add_octagonal_constraint(n_var, n_w+1, b, minus_den);
        }
      break;
    case LESS_OR_EQUAL:
      {
        PPL_DIRTY_TEMP(N, d);
        div_round_up(d, b, denominator);
        // Note that: `w_id != v', so that `expr' is of the form
        // w_coeff * w + b, with `w_id != v'.
        if (w_coeff == denominator) {
          // Add the new constraints `v - w <= b/denominator'.
          if (var_id < w_id)
            add_octagonal_constraint(n_w, n_var, d);
          else
            add_octagonal_constraint(n_var+1, n_w+1, d);
        }
        else if (w_coeff == minus_den) {
          // Add the new constraints `v + w <= b/denominator'.
          if (var_id < w_id)
            add_octagonal_constraint(n_w+1, n_var, d);
          else
            add_octagonal_constraint(n_var+1, n_w, d);
        }
        break;
      }

    case GREATER_OR_EQUAL:
      {
        PPL_DIRTY_TEMP(N, d);
        div_round_up(d, b, minus_den);
        // Note that: `w_id != v', so that `expr' is of the form
        // w_coeff * w + b, with `w_id != v'.
        if (w_coeff == denominator) {
          // Add the new constraint `v - w >= b/denominator',
          // i.e.,  `-v + w <= -b/denominator'.
          if (var_id < w_id)
            add_octagonal_constraint(n_w+1, n_var+1, d);
          else
            add_octagonal_constraint(n_var, n_w, d);
        }
        else if (w_coeff == minus_den) {
          // Add the new constraints `v + w >= b/denominator',
          // i.e.,  `-v - w <= -b/denominator'.
          if (var_id < w_id)
            add_octagonal_constraint(n_w, n_var+1, d);
          else
            add_octagonal_constraint(n_var, n_w+1, d);
        }
        break;
      }

    default:
      // We already dealt with the other cases.
      throw std::runtime_error("PPL internal error");
    }
  }
  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);
    PPL_DIRTY_TEMP_COEFFICIENT(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;

    PPL_DIRTY_TEMP(N, sum);
    // Index of variable that is unbounded in `this'.
    PPL_UNINITIALIZED(dimension_type, pinf_index);
    // Number of unbounded variables found.
    dimension_type pinf_count = 0;

    switch (relsym) {
    case EQUAL:
      {
        PPL_DIRTY_TEMP(N, neg_sum);
        // Index of variable that is unbounded in `this'.
        PPL_UNINITIALIZED(dimension_type, neg_pinf_index);
        // Number of unbounded variables found.
        dimension_type neg_pinf_count = 0;

        // Approximate the inhomogeneous term.
        assign_r(sum, sc_b, ROUND_UP);
        assign_r(neg_sum, minus_sc_b, ROUND_UP);

        // Approximate the homogeneous part of `sc_expr'.
        PPL_DIRTY_TEMP(N, coeff_i);
        PPL_DIRTY_TEMP(N, half);
        PPL_DIRTY_TEMP_COEFFICIENT(minus_sc_i);
        PPL_DIRTY_TEMP(N, minus_coeff_i);
        // Note: indices above `w' can be disregarded, as they all have
        // a zero coefficient in `sc_expr'.
        for (Row_iterator m_iter = m_begin, m_iter_end = m_iter + (2*w_id) + 2;
             m_iter != m_iter_end; ) {
          const dimension_type n_i = m_iter.index();
          const dimension_type id = n_i/2;
          Row_reference m_i = *m_iter;
          ++m_iter;
          Row_reference m_ci = *m_iter;
          ++m_iter;
          const Coefficient& sc_i = sc_expr.coefficient(Variable(id));
          const int sign_i = sgn(sc_i);
          if (sign_i > 0) {
            assign_r(coeff_i, sc_i, ROUND_UP);
            // Approximating `sc_expr'.
            if (pinf_count <= 1) {
              const N& double_approx_i = m_ci[n_i];
              if (!is_plus_infinity(double_approx_i)) {
                // Let half = double_approx_i / 2.
                div2exp_assign_r(half, double_approx_i, 1, ROUND_UP);
                add_mul_assign_r(sum, coeff_i, half, ROUND_UP);
              }
              else {
                ++pinf_count;
                pinf_index = id;
              }
            }
            // Approximating `-sc_expr'.
            if (neg_pinf_count <= 1) {
              const N& double_approx_minus_i = m_i[n_i+1];
              if (!is_plus_infinity(double_approx_minus_i)) {
                // Let half = double_approx_minus_i / 2.
                div2exp_assign_r(half, double_approx_minus_i, 1, ROUND_UP);
                add_mul_assign_r(neg_sum, coeff_i, half, ROUND_UP);
              }
              else {
                ++neg_pinf_count;
                neg_pinf_index = id;
              }
            }
          }
          else if (sign_i < 0) {
            neg_assign_r(minus_sc_i, sc_i, ROUND_NOT_NEEDED);
            assign_r(minus_coeff_i, minus_sc_i, ROUND_UP);
            // Approximating `sc_expr'.
            if (pinf_count <= 1) {
              const N& double_approx_minus_i = m_i[n_i+1];
              if (!is_plus_infinity(double_approx_minus_i)) {
                // Let half = double_approx_minus_i / 2.
                div2exp_assign_r(half, double_approx_minus_i, 1, ROUND_UP);
                add_mul_assign_r(sum, minus_coeff_i, half, ROUND_UP);
              }
              else {
                ++pinf_count;
                pinf_index = id;
              }
            }
            // Approximating `-sc_expr'.
            if (neg_pinf_count <= 1) {
              const N& double_approx_i = m_ci[n_i];
              if (!is_plus_infinity(double_approx_i)) {
                // Let half = double_approx_i / 2.
                div2exp_assign_r(half, double_approx_i, 1, ROUND_UP);
                add_mul_assign_r(neg_sum, minus_coeff_i, half, ROUND_UP);
              }
              else {
                ++neg_pinf_count;
                neg_pinf_index = id;
              }
            }
          }
        }
        // Return immediately if no approximation could be computed.
        if (pinf_count > 1 && neg_pinf_count > 1) {
          assert(OK());
          return;
        }

        // In the following, strong closure will be definitely lost.
        reset_strongly_closed();

        // Exploit the upper approximation, if possible.
        if (pinf_count <= 1) {
          // Compute quotient (if needed).
          if (sc_den != 1) {
            // 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.
            PPL_DIRTY_TEMP(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);
          }
          // Add the upper bound constraint, if meaningful.
          if (pinf_count == 0) {
            // Add the constraint `v <= sum'.
            PPL_DIRTY_TEMP(N, double_sum);
            mul2exp_assign_r(double_sum, sum, 1, ROUND_IGNORE);
            matrix[n_var+1][n_var] = double_sum;
            // Deduce constraints of the form `v +/- u', where `u != v'.
            deduce_v_pm_u_bounds(var_id, w_id, sc_expr, sc_den, sum);
          }
          else
            // Here `pinf_count == 1'.
            if (pinf_index != var_id) {
              const Coefficient& ppi =
                sc_expr.coefficient(Variable(pinf_index));
              if (ppi == sc_den)
                // Add the constraint `v - pinf_index <= sum'.
                if (var_id < pinf_index)
                  matrix[2*pinf_index][n_var] = sum;
                else
                  matrix[n_var+1][2*pinf_index+1] = sum;
              else
                if (ppi == minus_sc_den) {
                  // Add the constraint `v + pinf_index <= sum'.
                  if (var_id < pinf_index)
                    matrix[2*pinf_index+1][n_var] = sum;
                  else
                    matrix[n_var+1][2*pinf_index] = sum;
                }
            }
        }

        // Exploit the lower approximation, if possible.
        if (neg_pinf_count <= 1) {
          // Compute quotient (if needed).
          if (sc_den != 1) {
            // 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.
            PPL_DIRTY_TEMP(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(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'.
            PPL_DIRTY_TEMP(N, double_neg_sum);
            mul2exp_assign_r(double_neg_sum, neg_sum, 1, ROUND_IGNORE);
            matrix[n_var][n_var+1] = double_neg_sum;
            // Deduce constraints of the form `-v +/- u', where `u != v'.
            deduce_minus_v_pm_u_bounds(var_id, w_id, sc_expr, sc_den, neg_sum);
          }
          else
            // Here `neg_pinf_count == 1'.
            if (neg_pinf_index != var_id) {
              const Coefficient& npi =
                sc_expr.coefficient(Variable(neg_pinf_index));
              if (npi == sc_den)
                // Add the constraint `v - neg_pinf_index >= -neg_sum',
                // i.e., `neg_pinf_index - v <= neg_sum'.
                if (neg_pinf_index < var_id)
                  matrix[n_var][2*neg_pinf_index] = neg_sum;
                else
                  matrix[2*neg_pinf_index+1][n_var+1] = neg_sum;
              else
                if (npi == minus_sc_den) {
                  // Add the constraint `v + neg_pinf_index >= -neg_sum',
                  // i.e., `-neg_pinf_index - v <= neg_sum'.
                  if (neg_pinf_index < var_id)
                    matrix[n_var][2*neg_pinf_index+1] = neg_sum;
                  else
                    matrix[2*neg_pinf_index][n_var+1] = neg_sum;
                }
            }
        }
        break;
      }

    case LESS_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'.
        PPL_DIRTY_TEMP(N, coeff_i);
        PPL_DIRTY_TEMP(N, approx_i);
        PPL_DIRTY_TEMP_COEFFICIENT(minus_sc_i);
        // Note: indices above `w_id' can be disregarded, as they all have
        // a zero coefficient in `expr'.
        for (Row_Iterator m_iter = m_begin, m_end = m_iter + (2*w_id) + 2;
             m_iter != m_end; ) {
          const dimension_type n_i = m_iter.index();
          const dimension_type id = n_i/2;
          Row_Reference m_i = *m_iter;
          ++m_iter;
          Row_Reference m_ci = *m_iter;
          ++m_iter;
          const Coefficient& sc_i = sc_expr.coefficient(Variable(id));
          const int sign_i = sgn(sc_i);
          if (sign_i == 0)
            continue;
          // Choose carefully: we are approximating `sc_expr'.
          const N& double_approx_i = (sign_i > 0) ? m_ci[n_i] : m_i[n_i+1];
          if (is_plus_infinity(double_approx_i)) {
            if (++pinf_count > 1)
              break;
            pinf_index = id;
            continue;
          }
          if (sign_i > 0)
            assign_r(coeff_i, sc_i, ROUND_UP);
          else {
            neg_assign(minus_sc_i, sc_i);
            assign_r(coeff_i, minus_sc_i, ROUND_UP);
          }
          div2exp_assign_r(approx_i, double_approx_i, 1, 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.
          PPL_DIRTY_TEMP(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'.
          PPL_DIRTY_TEMP(N, double_sum);
          mul2exp_assign_r(double_sum, sum, 1, ROUND_IGNORE);
          add_octagonal_constraint(n_var+1, n_var, double_sum);
          // Deduce constraints of the form `v +/- u', where `u != v'.
          deduce_v_pm_u_bounds(var_id, w_id, sc_expr, sc_den, sum);
        }
        else if (pinf_count == 1) {
          dimension_type pinf_ind = 2*pinf_index;
          if (expr.coefficient(Variable(pinf_index)) == denominator ) {
            // Add the constraint `v - pinf_index <= sum'.
            if (var_id < pinf_index)
              add_octagonal_constraint(pinf_ind, n_var, sum);
            else
              add_octagonal_constraint(n_var+1, pinf_ind+1, sum);
          }
          else {
            if (expr.coefficient(Variable(pinf_index)) == minus_den) {
              // Add the constraint `v + pinf_index <= sum'.
              if (var_id < pinf_index)
                add_octagonal_constraint(pinf_ind+1, n_var, sum);
              else
                add_octagonal_constraint(n_var+1, pinf_ind, sum);
            }
          }
        }
        break;
      }

    case GREATER_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'.
        PPL_DIRTY_TEMP(N, coeff_i);
        PPL_DIRTY_TEMP(N, approx_i);
        PPL_DIRTY_TEMP_COEFFICIENT(minus_sc_i);
        for (Row_Iterator m_iter = m_begin, m_end = m_iter + (2*w_id) + 2;
             m_iter != m_end; ) {
          const dimension_type n_i = m_iter.index();
          const dimension_type id = n_i/2;
          Row_Reference m_i = *m_iter;
          ++m_iter;
          Row_Reference m_ci = *m_iter;
          ++m_iter;
          const Coefficient& sc_i = sc_expr.coefficient(Variable(id));
          const int sign_i = sgn(sc_i);
          if (sign_i == 0)
            continue;
          // Choose carefully: we are approximating `-sc_expr'.
          const N& double_approx_i = (sign_i > 0) ? m_i[n_i+1] : m_ci[n_i];
          if (is_plus_infinity(double_approx_i)) {
            if (++pinf_count > 1)
              break;
            pinf_index = id;
            continue;
          }
          if (sign_i > 0)
            assign_r(coeff_i, sc_i, ROUND_UP);
          else {
            neg_assign(minus_sc_i, sc_i);
            assign_r(coeff_i, minus_sc_i, ROUND_UP);
          }
          div2exp_assign_r(approx_i, double_approx_i, 1, 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.
          PPL_DIRTY_TEMP(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 >= -neg_sum', i.e., `-v <= neg_sum'.
          PPL_DIRTY_TEMP(N, double_sum);
          mul2exp_assign_r(double_sum, sum, 1, ROUND_IGNORE);
          add_octagonal_constraint(n_var, n_var+1, double_sum);
          // Deduce constraints of the form `-v +/- u', where `u != v'.
          deduce_minus_v_pm_u_bounds(var_id, pinf_index, sc_expr, sc_den, sum);
        }
        else if (pinf_count == 1) {
          dimension_type pinf_ind = 2*pinf_index;
          if (expr.coefficient(Variable(pinf_index)) == denominator) {
            // Add the constraint `v - pinf_index >= -sum',
            // i.e., `pinf_index - v <= sum'.
            if (pinf_index < var_id)
              add_octagonal_constraint(n_var, pinf_ind, sum);
            else
              add_octagonal_constraint(pinf_ind+1, n_var, sum);
          }
          else {
            if (expr.coefficient(Variable(pinf_index)) == minus_den) {
              // Add the constraint `v + pinf_index >= -sum',
              // i.e., `-pinf_index - v <= sum'.
              if (pinf_index < var_id)
                add_octagonal_constraint(n_var, pinf_ind+1, sum);
              else
                add_octagonal_constraint(pinf_ind, n_var+1, sum);
            }
          }
        }
        break;
      }

    default:
      // We already dealt with the other cases.
      throw std::runtime_error("PPL internal error");
    }
  }
}

template <typename T>
void
Octagonal_Shape<T>::affine_image(const Variable var,
                                 const Linear_Expression& expr,
                                 Coefficient_traits::const_reference
                                 denominator) {
  // 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 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 octagon.
  const dimension_type var_id = var.id();
  if (space_dim < var_id + 1)
    throw_dimension_incompatible("affine_image(v, e, d)", var.id()+1);

  strong_closure_assign();
  // The image of an empty octagon is empty too.
  if (marked_empty())
    return;

  // 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;
  // Variable-index of the last non-zero coefficient in `expr', if any.
  dimension_type w_id = 0;

  // Get information about the number of non-zero coefficients in `expr'.
  // The `expr' must not be in two or plus variables.
  for (dimension_type i = expr_space_dim; i-- > 0; )
    if (expr.coefficient(Variable(i)) != 0) {
      if (t++ == 1)
        break;
      else
        w_id = i;
    }

  typedef typename OR_Matrix<N>::row_iterator Row_Iterator;
  typedef typename OR_Matrix<N>::row_reference_type Row_Reference;
  typedef typename OR_Matrix<N>::const_row_iterator Row_iterator;
  typedef typename OR_Matrix<N>::const_row_reference_type Row_reference;

  const dimension_type n_var = 2*var_id;
  const Coefficient& b = expr.inhomogeneous_term();
  PPL_DIRTY_TEMP_COEFFICIENT(minus_den);
  neg_assign_r(minus_den, denominator, ROUND_NOT_NEEDED);

  // `w' is the variable with index `w_id'.
  // 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.

  if (t == 0) {
    // Case 1: expr == b.
    // Remove all constraints on `var'.
    forget_all_octagonal_constraints(var_id);
    PPL_DIRTY_TEMP_COEFFICIENT(two_b);
    two_b = 2*b;
    // Add the constraint `var == b/denominator'.
    add_octagonal_constraint(n_var+1, n_var, two_b, denominator);
    add_octagonal_constraint(n_var, n_var+1, two_b, minus_den);
    assert(OK());
    return;
  }

  if (t == 1) {
    // The one and only non-zero homogeneous coefficient in `expr'.
    const Coefficient& w_coeff = expr.coefficient(Variable(w_id));
    if (w_coeff == denominator || w_coeff == minus_den) {
      // Case 2: expr = w_coeff*w + b, with w_coeff = +/- denominator.
      if (w_id == var_id) {
        // Here `expr' is of the form: +/- denominator * v + b.
        if (w_coeff == 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'.
            PPL_DIRTY_TEMP(N, d);
            div_round_up(d, b, denominator);
            PPL_DIRTY_TEMP(N, minus_d);
            div_round_up(minus_d, b, minus_den);
            const Row_Iterator m_begin = matrix.row_begin();
            const Row_Iterator m_end = matrix.row_end();
            Row_Iterator m_iter = m_begin + n_var;
            Row_Reference m_v = *m_iter;
            ++m_iter;
            Row_Reference m_cv = *m_iter;
            ++m_iter;
            // NOTE: delay update of unary constraints on `var'.
            for (dimension_type j = n_var; j-- > 0; ) {
              N& m_v_j = m_v[j];
              add_assign_r(m_v_j, m_v_j, minus_d, ROUND_UP);
              N& m_cv_j = m_cv[j];
              add_assign_r(m_cv_j, m_cv_j, d, ROUND_UP);
            }
            for ( ; m_iter != m_end; ++m_iter) {
              Row_Reference m_i = *m_iter;
              N& m_i_v = m_i[n_var];
              add_assign_r(m_i_v, m_i_v, d, ROUND_UP);
              N& m_i_cv = m_i[n_var+1];
              add_assign_r(m_i_cv, m_i_cv, minus_d, ROUND_UP);
            }
            // Now update unary constraints on var.
            mul2exp_assign_r(d, d, 1, ROUND_IGNORE);
            N& m_cv_v = m_cv[n_var];
            add_assign_r(m_cv_v, m_cv_v, d, ROUND_UP);
            mul2exp_assign_r(minus_d, minus_d, 1, ROUND_IGNORE);
            N& m_v_cv = m_v[n_var+1];
            add_assign_r(m_v_cv, m_v_cv, minus_d, ROUND_UP);
           }
          reset_strongly_closed();
        }
        else {
          // Here `w_coeff == -denominator'.
          // Remove the binary constraints on `var'.
          forget_binary_octagonal_constraints(var_id);
          const Row_Iterator m_begin = matrix.row_begin();
          Row_Iterator m_iter = m_begin + n_var;
          N& m_v_cv = (*m_iter)[n_var+1];
          ++m_iter;
          N& m_cv_v = (*m_iter)[n_var];
          // Swap the unary constraints on `var'.
          std::swap(m_v_cv, m_cv_v);
          // Strong closure is not preserved.
          reset_strongly_closed();
          if (b != 0) {
            // Translate the unary constraints on `var',
            // adding or subtracting the value `b/denominator'.
            PPL_DIRTY_TEMP(N, d);
            div_round_up(d, b, denominator);
            mul2exp_assign_r(d, d, 1, ROUND_IGNORE);
            add_assign_r(m_cv_v, m_cv_v, d, ROUND_UP);
            PPL_DIRTY_TEMP(N, minus_d);
            div_round_up(minus_d, b, minus_den);
            mul2exp_assign_r(minus_d, minus_d, 1, ROUND_IGNORE);
            add_assign_r(m_v_cv, m_v_cv, minus_d, ROUND_UP);
          }
          incremental_strong_closure_assign(var);
         }
      }
      else {
        // Here `w != var', so that `expr' is of the form
        // +/-denominator * w + b.
        // Remove all constraints on `var'.
        forget_all_octagonal_constraints(var_id);
        const dimension_type n_w = 2*w_id;
        // Add the new constraint `var - w = b/denominator'.
        if (w_coeff == denominator)
          if (var_id < w_id) {
            add_octagonal_constraint(n_w, n_var, b, denominator);
            add_octagonal_constraint(n_w+1, n_var+1, b, minus_den);
          }
          else {
            add_octagonal_constraint(n_var+1, n_w+1, b, denominator);
            add_octagonal_constraint(n_var, n_w, b, minus_den);
          }
        else
          // Add the new constraint `var + w = b/denominator'.
          if (var_id < w_id) {
            add_octagonal_constraint(n_w+1, n_var, b, denominator);
            add_octagonal_constraint(n_w, n_var+1, b, minus_den);
          }
          else {
            add_octagonal_constraint(n_var+1, n_w, b, denominator);
            add_octagonal_constraint(n_var, n_w+1, b, minus_den);
          }
        incremental_strong_closure_assign(var);
      }
      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);
  PPL_DIRTY_TEMP_COEFFICIENT(minus_b);
  neg_assign_r(minus_b, b, ROUND_NOT_NEEDED);

  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;

  PPL_DIRTY_TEMP(N, pos_sum);
  PPL_DIRTY_TEMP(N, neg_sum);
  // Indices of the variables that are unbounded in `this->matrix'.
  PPL_UNINITIALIZED(dimension_type, pos_pinf_index);
  PPL_UNINITIALIZED(dimension_type, neg_pinf_index);
  // 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'.
  PPL_DIRTY_TEMP(N, coeff_i);
  PPL_DIRTY_TEMP(N, minus_coeff_i);
  PPL_DIRTY_TEMP(N, half);
  PPL_DIRTY_TEMP_COEFFICIENT(minus_sc_i);
  // Note: indices above `w' can be disregarded, as they all have
  // a zero coefficient in `sc_expr'.
  const Row_Iterator m_begin = matrix.row_begin();
  for (Row_iterator m_iter = m_begin,
         m_iter_end = m_iter + (2*w_id) + 2; m_iter != m_iter_end; ) {
    const dimension_type n_i = m_iter.index();
    const dimension_type id = n_i/2;
    Row_reference m_i = *m_iter;
    ++m_iter;
    Row_reference m_ci = *m_iter;
    ++m_iter;
    const Coefficient& sc_i = sc_expr.coefficient(Variable(id));
    const int sign_i = sgn(sc_i);
    if (sign_i > 0) {
      assign_r(coeff_i, sc_i, ROUND_UP);
      // Approximating `sc_expr'.
      if (pos_pinf_count <= 1) {
        const N& double_up_approx_i = m_ci[n_i];
        if (!is_plus_infinity(double_up_approx_i)) {
          // Let half = double_up_approx_i / 2.
          div2exp_assign_r(half, double_up_approx_i, 1, ROUND_UP);
          add_mul_assign_r(pos_sum, coeff_i, half, ROUND_UP);
        }
        else {
          ++pos_pinf_count;
          pos_pinf_index = id;
        }
      }
      // Approximating `-sc_expr'.
      if (neg_pinf_count <= 1) {
        const N& double_up_approx_minus_i = m_i[n_i+1];
        if (!is_plus_infinity(double_up_approx_minus_i)) {
          // Let half = double_up_approx_minus_i / 2.
          div2exp_assign_r(half, double_up_approx_minus_i, 1, ROUND_UP);
          add_mul_assign_r(neg_sum, coeff_i, half, ROUND_UP);
        }
        else {
          ++neg_pinf_count;
          neg_pinf_index = id;
        }
      }
    }
    else if (sign_i < 0) {
      neg_assign_r(minus_sc_i, sc_i, ROUND_NOT_NEEDED);
      assign_r(minus_coeff_i, minus_sc_i, ROUND_UP);
      // Approximating `sc_expr'.
      if (pos_pinf_count <= 1) {
        const N& double_up_approx_minus_i = m_i[n_i+1];
        if (!is_plus_infinity(double_up_approx_minus_i)) {
          // Let half = double_up_approx_minus_i / 2.
          div2exp_assign_r(half, double_up_approx_minus_i, 1, ROUND_UP);
          add_mul_assign_r(pos_sum, minus_coeff_i, half, ROUND_UP);
        }
        else {
          ++pos_pinf_count;
          pos_pinf_index = id;
        }
      }
      // Approximating `-sc_expr'.
      if (neg_pinf_count <= 1) {
        const N& double_up_approx_i = m_ci[n_i];
        if (!is_plus_infinity(double_up_approx_i)) {
          // Let half = double_up_approx_i / 2.
          div2exp_assign_r(half, double_up_approx_i, 1, ROUND_UP);
          add_mul_assign_r(neg_sum, minus_coeff_i, half, ROUND_UP);
        }
        else {
          ++neg_pinf_count;
          neg_pinf_index = id;
        }
      }
    }
  }

  // Remove all constraints on `var'.
  forget_all_octagonal_constraints(var_id);
  // Return immediately if no approximation could be computed.
  if (pos_pinf_count > 1 && neg_pinf_count > 1) {
    assert(OK());
    return;
  }

  // In the following, strong closure will be definitely lost.
  reset_strongly_closed();

  // Exploit the upper approximation, if possible.
  if (pos_pinf_count <= 1) {
    // Compute quotient (if needed).
    if (sc_den != 1) {
      // 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.
      PPL_DIRTY_TEMP(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(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'.
      PPL_DIRTY_TEMP(N, double_pos_sum);
      mul2exp_assign_r(double_pos_sum, pos_sum, 1, ROUND_IGNORE);
      matrix[n_var+1][n_var] = double_pos_sum;
      // Deduce constraints of the form `v +/- u', where `u != v'.
      deduce_v_pm_u_bounds(var_id, w_id, sc_expr, sc_den, pos_sum);
    }
    else
      // Here `pos_pinf_count == 1'.
      if (pos_pinf_index != var_id) {
        const Coefficient& ppi = sc_expr.coefficient(Variable(pos_pinf_index));
        if (ppi == sc_den)
          // Add the constraint `v - pos_pinf_index <= pos_sum'.
          if (var_id < pos_pinf_index)
            matrix[2*pos_pinf_index][n_var] = pos_sum;
          else
            matrix[n_var+1][2*pos_pinf_index+1] = pos_sum;
        else
          if (ppi == minus_sc_den) {
            // Add the constraint `v + pos_pinf_index <= pos_sum'.
            if (var_id < pos_pinf_index)
              matrix[2*pos_pinf_index+1][n_var] = pos_sum;
            else
              matrix[n_var+1][2*pos_pinf_index] = pos_sum;
          }
      }
  }

  // Exploit the lower approximation, if possible.
  if (neg_pinf_count <= 1) {
    // Compute quotient (if needed).
    if (sc_den != 1) {
      // 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.
      PPL_DIRTY_TEMP(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(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'.
      PPL_DIRTY_TEMP(N, double_neg_sum);
      mul2exp_assign_r(double_neg_sum, neg_sum, 1, ROUND_IGNORE);
      matrix[n_var][n_var+1] = double_neg_sum;
      // Deduce constraints of the form `-v +/- u', where `u != v'.
      deduce_minus_v_pm_u_bounds(var_id, w_id, sc_expr, sc_den, neg_sum);
    }
    else
      // Here `neg_pinf_count == 1'.
      if (neg_pinf_index != var_id) {
        const Coefficient& npi = sc_expr.coefficient(Variable(neg_pinf_index));
        if (npi == sc_den)
          // Add the constraint `v - neg_pinf_index >= -neg_sum',
          // i.e., `neg_pinf_index - v <= neg_sum'.
          if (neg_pinf_index < var_id)
            matrix[n_var][2*neg_pinf_index] = neg_sum;
          else
            matrix[2*neg_pinf_index+1][n_var+1] = neg_sum;
        else
          if (npi == minus_sc_den) {
            // Add the constraint `v + neg_pinf_index >= -neg_sum',
            // i.e., `-neg_pinf_index - v <= neg_sum'.
            if (neg_pinf_index < var_id)
              matrix[n_var][2*neg_pinf_index+1] = neg_sum;
            else
              matrix[2*neg_pinf_index][n_var+1] = neg_sum;
          }
      }
  }

  incremental_strong_closure_assign(var);
  assert(OK());
}

template <typename T>
void
Octagonal_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 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 octagon.
  dimension_type var_id = var.id();
  if (space_dim < var_id + 1)
    throw_dimension_incompatible("affine_preimage(v, e, d)", var.id()+1);

  strong_closure_assign();
  // The image of an empty octagon is empty too.
  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;

  // Variable-index of the last non-zero coefficient in `expr', if any.
  dimension_type w_id = 0;

  // Get information about the number of the non-zero coefficients of `expr'.
  for (dimension_type i = expr_space_dim; i-- > 0; )
    if (expr.coefficient(Variable(i)) != 0) {
      if (t++ == 1)
        break;
      else
        w_id = i;
    }

  // `w' is the variable with index `w_id'.
  // 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.

  if (t == 0) {
    // Case 1: expr = n; remove all constraints on `var'.
    forget_all_octagonal_constraints(var_id);
    assert(OK());
    return;
  }

  if (t == 1) {
    // Value of the one and only non-zero coefficient in `expr'.
    const Coefficient& w_coeff = expr.coefficient(Variable(w_id));
    if (w_coeff == denominator || w_coeff == -denominator) {
      // Case 2: expr = w_coeff*w + b, with w_coeff = +/- denominator.
      if (w_id == var_id) {
        // Apply affine_image() on the inverse of this transformation.
        affine_image(var, denominator*var - b, w_coeff);
      }
      else {
        // `expr == w_coeff*w + b', where `w != var'.
        // Remove all constraints on `var'.
        forget_all_octagonal_constraints(var_id);
        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& coeff_v = expr.coefficient(var);
  if (coeff_v != 0) {
    if (coeff_v > 0) {
      // The transformation is invertible.
      Linear_Expression inverse = ((coeff_v + denominator)*var);
      inverse -= expr;
      affine_image(var, inverse, coeff_v);
    }
    else {
      // The transformation is invertible.
      PPL_DIRTY_TEMP_COEFFICIENT(minus_coeff_v);
      neg_assign(minus_coeff_v, coeff_v);
      Linear_Expression inverse = ((minus_coeff_v - denominator)*var);
      inverse += expr;
      affine_image(var, inverse, minus_coeff_v);
    }
  }
  else {
    // The transformation is not invertible: all constraints on `var' are lost.
    forget_all_octagonal_constraints(var_id);
    assert(OK());
  }
}

template <typename T>
void
Octagonal_Shape<T>
::generalized_affine_image(const Variable var,
                           const Relation_Symbol relsym,
                           const Linear_Expression&  expr ,
                           Coefficient_traits::const_reference denominator) {
  // 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 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 octagon.
  dimension_type var_id = var.id();
  if (space_dim < var_id + 1)
    throw_dimension_incompatible("generalized_affine_image(v, r, e, d)",
                                 var.id()+1);

  // 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 an Octagonal_Shape");

  if (relsym == EQUAL) {
    // The relation symbol is "==":
    // this is just an affine image computation.
    affine_image(var, expr, denominator);
    return;
  }

  strong_closure_assign();
  // The image of an empty octagon is empty too.
  if (marked_empty())
    return;

  // 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;
  // Variable-index of the last non-zero coefficient in `expr', if any.
  dimension_type w_id = 0;

  // Get information about the number of non-zero coefficients in `expr'.
  // The `expr' must not be in two or plus variables.
  for (dimension_type i = expr_space_dim; i-- > 0; )
    if (expr.coefficient(Variable(i)) != 0) {
      if (t++ == 1)
        break;
      else
        w_id = i;
    }

  typedef typename OR_Matrix<N>::row_iterator Row_Iterator;
  typedef typename OR_Matrix<N>::row_reference_type Row_Reference;
  typedef typename OR_Matrix<N>::const_row_iterator Row_iterator;
  typedef typename OR_Matrix<N>::const_row_reference_type Row_reference;

  const Row_Iterator m_begin = matrix.row_begin();
  const Row_Iterator m_end = matrix.row_end();
  const dimension_type n_var = 2*var_id;
  const Coefficient& b = expr.inhomogeneous_term();
  PPL_DIRTY_TEMP_COEFFICIENT(minus_den);
  neg_assign_r(minus_den, denominator, ROUND_NOT_NEEDED);

  // `w' is the variable with index `w_id'.
  // 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.

  if (t == 0) {
    // Case 1: expr = b.
    PPL_DIRTY_TEMP_COEFFICIENT(two_b);
    two_b = 2*b;
    // Remove all constraints on `var'.
    forget_all_octagonal_constraints(var_id);
    // Strong closure is lost.
    reset_strongly_closed();
    switch (relsym) {
    case LESS_OR_EQUAL:
      // Add the constraint `var <= b/denominator'.
      add_octagonal_constraint(n_var+1, n_var, two_b, denominator);
      break;
    case GREATER_OR_EQUAL:
      // Add the constraint `var >= n/denominator',
      // i.e., `-var <= -b/denominator'.
      add_octagonal_constraint(n_var, n_var+1, two_b, minus_den);
      break;
    default:
      // We already dealt with the other cases.
      throw std::runtime_error("PPL internal error");
    }
    assert(OK());
    return;
  }

  if (t == 1) {
    // The one and only non-zero homogeneous coefficient in `expr'.
    const Coefficient& w_coeff = expr.coefficient(Variable(w_id));
    if (w_coeff == denominator || w_coeff == minus_den) {
      // Case 2: expr == w_coeff*w + b, with w_coeff == +/- denominator.
      switch (relsym) {
      case LESS_OR_EQUAL:
        {
          PPL_DIRTY_TEMP(N, d);
          div_round_up(d, b, denominator);
          if (w_id == var_id) {
            // Here `expr' is of the form: +/- denominator * v + b.
            // Strong closure is not preserved.
            reset_strongly_closed();
            if (w_coeff == denominator) {
              // Translate all the constraints of the form `v - w <= cost'
              // into the constraint `v - w <= cost + b/denominator';
              // forget each constraint `w - v <= cost1'.
              Row_Iterator m_iter = m_begin + n_var;
              Row_Reference m_v = *m_iter;
              N& m_v_cv = m_v[n_var+1];
              ++m_iter;
              Row_Reference m_cv = *m_iter;
              N& m_cv_v = m_cv[n_var];
              ++m_iter;
              // NOTE: delay update of m_v_cv and m_cv_v.
              for ( ; m_iter != m_end; ++m_iter) {
                Row_Reference m_i = *m_iter;
                N& m_i_v = m_i[n_var];
                add_assign_r(m_i_v, m_i_v, d, ROUND_UP);
                assign_r(m_i[n_var+1], PLUS_INFINITY, ROUND_NOT_NEEDED);
              }
              for (dimension_type k = n_var; k-- > 0; ) {
                assign_r(m_v[k], PLUS_INFINITY, ROUND_NOT_NEEDED);
                add_assign_r(m_cv[k], m_cv[k], d, ROUND_UP);
              }
              mul2exp_assign_r(d, d, 1, ROUND_IGNORE);
              add_assign_r(m_cv_v, m_cv_v, d, ROUND_UP);
              assign_r(m_v_cv, PLUS_INFINITY, ROUND_NOT_NEEDED);
            }
            else {
              // Here `w_coeff == -denominator'.
              // `expr' is of the form: -a*var + b.
              N& m_v_cv = matrix[n_var][n_var+1];
              mul2exp_assign_r(d, d, 1, ROUND_IGNORE);
              add_assign_r(matrix[n_var+1][n_var], m_v_cv, d, ROUND_UP);
              assign_r(m_v_cv, PLUS_INFINITY, ROUND_NOT_NEEDED);
              forget_binary_octagonal_constraints(var_id);
            }
          }
          else {
            // Here `w != v', so that `expr' is the form
            // +/- denominator*w + b.
            // Remove all constraints on `v'.
            forget_all_octagonal_constraints(var_id);
            const dimension_type n_w = 2*w_id;
            if (w_coeff == denominator) {
              // Add the new constraint `v - w <= b/denominator'.
              if (var_id < w_id)
                add_octagonal_constraint(n_w, n_var, b, denominator);
              else
                add_octagonal_constraint(n_var+1, n_w+1, b, denominator);
            }
            else {
              // Add the new constraint `v + w <= b/denominator'.
              if (var_id < w_id)
                add_octagonal_constraint(n_w+1, n_var, b, denominator);
              else
                add_octagonal_constraint(n_var+1, n_w, b, denominator);
            }
          }
          break;
        }

      case GREATER_OR_EQUAL:
        {
          PPL_DIRTY_TEMP(N, d);
          div_round_up(d, b, minus_den);
          if (w_id == var_id) {
            // Here `expr' is of the form: +/- denominator * v + b.
            // Strong closure is not preserved.
            reset_strongly_closed();
            if (w_coeff == denominator) {
              // Translate each constraint `w - v <= cost'
              // into the constraint `w - v <= cost - b/denominator';
              // forget each constraint `v - w <= cost1'.
              Row_Iterator m_iter = m_begin + n_var;
              Row_Reference m_v = *m_iter;
              N& m_v_cv = m_v[n_var+1];
              ++m_iter;
              Row_Reference m_cv = *m_iter;
              N& m_cv_v = m_cv[n_var];
              ++m_iter;
              // NOTE: delay update of m_v_cv and m_cv_v.
              for ( ; m_iter != m_end; ++m_iter) {
                Row_Reference m_i = *m_iter;
                assign_r(m_i[n_var], PLUS_INFINITY, ROUND_NOT_NEEDED);
                add_assign_r(m_i[n_var+1], m_i[n_var+1], d, ROUND_UP);
              }
              for (dimension_type k = n_var; k-- > 0; ) {
                add_assign_r(m_v[k], m_v[k], d, ROUND_UP);
                assign_r(m_cv[k], PLUS_INFINITY, ROUND_NOT_NEEDED);
              }
              mul2exp_assign_r(d, d, 1, ROUND_IGNORE);
              add_assign_r(m_v_cv, m_v_cv, d, ROUND_UP);
              assign_r(m_cv_v, PLUS_INFINITY, ROUND_NOT_NEEDED);
            }
            else {
              // Here `w_coeff == -denominator'.
              // `expr' is of the form: -a*var + b.
              N& m_cv_v = matrix[n_var+1][n_var];
              mul2exp_assign_r(d, d, 1, ROUND_IGNORE);
              add_assign_r(matrix[n_var][n_var+1], m_cv_v, d, ROUND_UP);
              assign_r(m_cv_v, PLUS_INFINITY, ROUND_NOT_NEEDED);
              forget_binary_octagonal_constraints(var_id);
            }
          }
          else {
            // Here `w != v', so that `expr' is of the form
            // +/-denominator * w + b, with `w != v'.
            // Remove all constraints on `v'.
            forget_all_octagonal_constraints(var_id);
            const dimension_type n_w = 2*w_id;
            // We have got an expression of the following form:
            // var1 + n, with `var1' != `var'.
            // We remove all constraints of the form `var (+/- var1) >= const'
            // and we add the new constraint `var +/- var1 >= n/denominator'.
            if (w_coeff == denominator) {
              // Add the new constraint `var - w >= b/denominator',
              // i.e., `w - var <= -b/denominator'.
              if (var_id < w_id)
                add_octagonal_constraint(n_w+1, n_var+1, b, minus_den);
              else
                add_octagonal_constraint(n_var, n_w, b, minus_den);
            }
            else {
              // Add the new constraint `var + w >= b/denominator',
              // i.e., `-w - var <= -b/denominator'.
              if (var_id < w_id)
                add_octagonal_constraint(n_w, n_var+1, b, minus_den);
              else
                add_octagonal_constraint(n_var, n_w+1, b, minus_den);
            }
          }
          break;
        }

      default:
        // We already dealt with the other cases.
        throw std::runtime_error("PPL internal error");
      }
      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);
  PPL_DIRTY_TEMP_COEFFICIENT(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;

  PPL_DIRTY_TEMP(N, sum);
  // Index of variable that is unbounded in `this->matrix'.
  PPL_UNINITIALIZED(dimension_type, pinf_index);
  // Number of unbounded variables found.
  dimension_type pinf_count = 0;

  switch (relsym) {
  case LESS_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'.
      PPL_DIRTY_TEMP(N, coeff_i);
      PPL_DIRTY_TEMP(N, approx_i);
      PPL_DIRTY_TEMP_COEFFICIENT(minus_sc_i);
      // Note: indices above `w' can be disregarded, as they all have
      // a zero coefficient in `sc_expr'.
      for (Row_iterator m_iter = m_begin, m_iter_end = m_iter + (2*w_id) + 2;
           m_iter != m_iter_end; ) {
        const dimension_type n_i = m_iter.index();
        const dimension_type id = n_i/2;
        Row_reference m_i = *m_iter;
        ++m_iter;
        Row_reference m_ci = *m_iter;
        ++m_iter;
        const Coefficient& sc_i = sc_expr.coefficient(Variable(id));
        const int sign_i = sgn(sc_i);
        if (sign_i == 0)
          continue;
        // Choose carefully: we are approximating `sc_expr'.
        const N& double_approx_i = (sign_i > 0) ? m_ci[n_i] : m_i[n_i+1];
        if (is_plus_infinity(double_approx_i)) {
          if (++pinf_count > 1)
            break;
          pinf_index = id;
          continue;
        }
        if (sign_i > 0)
          assign_r(coeff_i, sc_i, ROUND_UP);
        else {
          neg_assign(minus_sc_i, sc_i);
          assign_r(coeff_i, minus_sc_i, ROUND_UP);
        }
        div2exp_assign_r(approx_i, double_approx_i, 1, ROUND_UP);
        add_mul_assign_r(sum, coeff_i, approx_i, ROUND_UP);
      }
      // Remove all constraints on `v'.
      forget_all_octagonal_constraints(var_id);
      reset_strongly_closed();
      // 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.
        PPL_DIRTY_TEMP(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 <= pos_sum'.
        PPL_DIRTY_TEMP(N, double_sum);
        mul2exp_assign_r(double_sum, sum, 1, ROUND_IGNORE);
        matrix[n_var+1][n_var] = double_sum;
        // Deduce constraints of the form `v +/- u', where `u != v'.
        deduce_v_pm_u_bounds(var_id, w_id, sc_expr, sc_den, sum);
      }
      else if (pinf_count == 1)
        if (pinf_index != var_id) {
          const Coefficient& pi = expr.coefficient(Variable(pinf_index));
          if (pi == denominator ) {
            // Add the constraint `v - pinf_index <= sum'.
            if (var_id < pinf_index)
              matrix[2*pinf_index][n_var] = sum;
            else
              matrix[n_var+1][2*pinf_index+1] = sum;
          }
          else {
            if (pi == minus_den) {
              // Add the constraint `v + pinf_index <= sum'.
              if (var_id < pinf_index)
                matrix[2*pinf_index+1][n_var] = sum;
              else
                matrix[n_var+1][2*pinf_index] = sum;
            }
          }
        }
      break;
    }

  case GREATER_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);
      PPL_DIRTY_TEMP(N, coeff_i);
      PPL_DIRTY_TEMP_COEFFICIENT(minus_sc_i);
      PPL_DIRTY_TEMP(N, approx_i);
      // Approximate the homogeneous part of `-sc_expr'.
      for (Row_iterator m_iter = m_begin, m_iter_end = m_iter + (2*w_id) + 2;
           m_iter != m_iter_end; ) {
        const dimension_type n_i = m_iter.index();
        const dimension_type id = n_i/2;
        Row_reference m_i = *m_iter;
        ++m_iter;
        Row_reference m_ci = *m_iter;
        ++m_iter;
        const Coefficient& sc_i = sc_expr.coefficient(Variable(id));
        const int sign_i = sgn(sc_i);
        if (sign_i == 0)
          continue;
        // Choose carefully: we are approximating `-sc_expr'.
        const N& double_approx_i = (sign_i > 0) ? m_i[n_i+1] : m_ci[n_i];
        if (is_plus_infinity(double_approx_i)) {
          if (++pinf_count > 1)
            break;
          pinf_index = id;
          continue;
        }
        if (sign_i > 0)
          assign_r(coeff_i, sc_i, ROUND_UP);
        else {
          neg_assign(minus_sc_i, sc_i);
          assign_r(coeff_i, minus_sc_i, ROUND_UP);
        }
        div2exp_assign_r(approx_i, double_approx_i, 1, ROUND_UP);
        add_mul_assign_r(sum, coeff_i, approx_i, ROUND_UP);
      }

      // Remove all constraints on `var'.
      forget_all_octagonal_constraints(var_id);
      reset_strongly_closed();
      // 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.
        PPL_DIRTY_TEMP(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 >= -neg_sum', i.e., `-v <= neg_sum'.
        PPL_DIRTY_TEMP(N, double_sum);
        mul2exp_assign_r(double_sum, sum, 1, ROUND_IGNORE);
        matrix[n_var][n_var+1] = double_sum;
        // Deduce constraints of the form `-v +/- u', where `u != v'.
        deduce_minus_v_pm_u_bounds(var_id, pinf_index, sc_expr, sc_den, sum);
      }
      else if (pinf_count == 1)
        if (pinf_index != var_id) {
          const Coefficient& pi = expr.coefficient(Variable(pinf_index));
          if (pi == denominator) {
            // Add the constraint `v - pinf_index >= -sum',
            // i.e., `pinf_index - v <= sum'.
            if (pinf_index < var_id)
              matrix[n_var][2*pinf_index] = sum;
            else
              matrix[2*pinf_index+1][n_var+1] = sum;
          }
          else {
            if (pi == minus_den) {
              // Add the constraint `v + pinf_index >= -sum',
              // i.e., `-pinf_index - v <= sum'.
              if (pinf_index < var_id)
                matrix[n_var][2*pinf_index+1] = sum;
              else
                matrix[2*pinf_index][n_var+1] = sum;
            }
          }
        }
      break;
    }

  default:
    // We already dealt with the other cases.
    throw std::runtime_error("PPL internal error");
  }
  incremental_strong_closure_assign(var);
  assert(OK());
}

template <typename T>
void
Octagonal_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'.
  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 octagons.
  if (relsym == LESS_THAN || relsym == GREATER_THAN)
    throw_generic("generalized_affine_image(e1, r, e2)",
                  "r is a strict relation symbol and "
                  "*this is an Octagonal_Shape");

  strong_closure_assign();
  // The image of an empty octagon is empty.
  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 an octagonal difference if `t_rhs <= 1'
    // or `t_rhs > 1' and `rhs == a*v - a*w + b_rhs' or
    // `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 an octagonal difference, should we compute
    // approximations for this constraint?
    switch (relsym) {
    case LESS_OR_EQUAL:
      refine_no_check(lhs <= rhs);
      break;
    case EQUAL:
      refine_no_check(lhs == rhs);
      break;
    case GREATER_OR_EQUAL:
      refine_no_check(lhs >= rhs);
      break;
    default:
      // We already dealt with the other cases.
      throw std::runtime_error("PPL internal error");
    }
  }

  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_OR_EQUAL)
        new_relsym = GREATER_OR_EQUAL;
      else if (relsym == GREATER_OR_EQUAL)
        new_relsym = LESS_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.
      // Existentially quantify all variables in the lhs.
      for (dimension_type i = lhs_vars.size(); i-- > 0; ) {
        dimension_type lhs_vars_i = lhs_vars[i].id();
        forget_all_octagonal_constraints(lhs_vars_i);
      }
      // 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 an octagonal difference,
      // it will be simply ignored. Should we compute approximations for it?
      switch (relsym) {
      case LESS_OR_EQUAL:
        refine_no_check(lhs <= rhs);
        break;
      case EQUAL:
        refine_no_check(lhs == rhs);
        break;
      case GREATER_OR_EQUAL:
        refine_no_check(lhs >= rhs);
        break;
      default:
        // We already dealt with the other cases.
        throw std::runtime_error("PPL internal error");
      }
    }
    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; ) {
        dimension_type lhs_vars_i = lhs_vars[i].id();
        forget_all_octagonal_constraints(lhs_vars_i);
      }

#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 refine_no_check()
      // ensures some approximation is tried even when the constraint
      // is not an octagonal constraint.
      affine_image(new_var, rhs);
      // Existentially quantify all variables in the lhs.
      // NOTE: enforce strong closure for precision.
      strong_closure_assign();
      assert(!marked_empty());
      for (dimension_type i = lhs_vars.size(); i-- > 0; ) {
        dimension_type lhs_vars_i = lhs_vars[i].id();
        forget_all_octagonal_constraints(lhs_vars_i);
      }
      // 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
      // an octagonal difference (since it has 3 variables at least).
      // Thus, the method refine_no_check() will simply ignore it.
      // Should we compute approximations for this constraint?
      switch (relsym) {
      case LESS_OR_EQUAL:
        refine_no_check(lhs <= new_var);
        break;
      case EQUAL:
        refine_no_check(lhs == new_var);
        break;
      case GREATER_OR_EQUAL:
        refine_no_check(lhs >= new_var);
        break;
      default:
        // We already dealt with the other cases.
        throw std::runtime_error("PPL internal error");
      }
      // Remove the temporarily added dimension.
      remove_higher_space_dimensions(space_dim-1);
#endif // Currently unnecessarily complex computation.
    }
  }

  assert(OK());
}

template <typename T>
void
Octagonal_Shape<T>::bounded_affine_image(const Variable var,
                                         const Linear_Expression& lb_expr,
                                         const Linear_Expression& ub_expr,
                                         Coefficient_traits::const_reference
                                         denominator) {
  // The denominator cannot be zero.
  if (denominator == 0)
    throw_generic("bounded_affine_image(v, lb, ub, d)", "d == 0");

  // `var' should be one of the dimensions of the octagon.
  const dimension_type var_id = var.id();
  if (space_dim < var_id + 1)
    throw_dimension_incompatible("bounded_affine_image(v, lb, ub, d)",
                                 var.id()+1);

  // The dimension of `lb_expr' and `ub_expr' should not be
  // greater than the dimension of `*this'.
  const dimension_type lb_space_dim = lb_expr.space_dimension();
  if (space_dim < lb_space_dim)
    throw_dimension_incompatible("bounded_affine_image(v, lb, ub)",
                                 "lb", lb_expr);
  const dimension_type ub_space_dim = ub_expr.space_dimension();
  if (space_dim < ub_space_dim)
    throw_dimension_incompatible("bounded_affine_image(v, lb, ub)",
                                 "ub", ub_expr);

  strong_closure_assign();
  // The image of an empty octagon is empty too.
  if (marked_empty())
    return;

  // Number of non-zero coefficients in `lb_expr': will be set to
  // 0, 1, or 2, the latter value meaning any value greater than 1.
  dimension_type t = 0;
  // Variable-index of the last non-zero coefficient in `lb_expr', if any.
  dimension_type w_id = 0;

  // Get information about the number of non-zero coefficients in `lb_expr'.
  // The `expr' must not be in two or plus variables.
  for (dimension_type i = lb_space_dim; i-- > 0; )
    if (lb_expr.coefficient(Variable(i)) != 0) {
      if (t++ == 1)
        break;
      else
        w_id = i;
    }

  typedef typename OR_Matrix<N>::row_iterator Row_Iterator;
  typedef typename OR_Matrix<N>::row_reference_type Row_Reference;
  typedef typename OR_Matrix<N>::const_row_iterator Row_iterator;
  typedef typename OR_Matrix<N>::const_row_reference_type Row_reference;

  const Row_Iterator m_begin = matrix.row_begin();
  const dimension_type n_var = 2*var_id;
  const Coefficient& b = lb_expr.inhomogeneous_term();
  PPL_DIRTY_TEMP_COEFFICIENT(minus_den);
  neg_assign_r(minus_den, denominator, ROUND_NOT_NEEDED);

  // `w' is the variable with index `w_id'.
  // Now we know the form of `lb_expr':
  // - If t == 0, then lb_expr == b, with `b' a constant;
  // - If t == 1, then lb_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 `lb_expr' is of the general form.

  if (t == 0) {
    // Case 1: lb_expr == b.
    generalized_affine_image(var,
                             LESS_OR_EQUAL,
                             ub_expr,
                             denominator);
    PPL_DIRTY_TEMP_COEFFICIENT(two_b);
    two_b = 2*b;
    // Add the constraint `var >= b/denominator'.
    add_octagonal_constraint(n_var, n_var+1, two_b, minus_den);
    assert(OK());
    return;
  }

  if (t == 1) {
    // The one and only non-zero homogeneous coefficient in `lb_expr'.
    const Coefficient& w_coeff = lb_expr.coefficient(Variable(w_id));
    if (w_coeff == denominator || w_coeff == minus_den) {
      // Case 2: lb_expr = w_coeff*w + b, with w_coeff = +/- denominator.
     if (w_id == var_id) {
        // Here `var' occurs in `lb_expr'.
        // 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 `lb_expr'.
        // Here `lb_expr' is of the form: +/- denominator * v + b.
        affine_image(new_var, lb_expr, denominator);
        // Enforce the strong closure for precision.
        strong_closure_assign();
        assert(!marked_empty());
        // Apply the affine upper bound.
        generalized_affine_image(var,
                                 LESS_OR_EQUAL,
                                 ub_expr,
                                 denominator);
        // Now apply the affine lower bound, as recorded in `new_var'
        refine_no_check(var >= new_var);
        // Remove the temporarily added dimension.
        remove_higher_space_dimensions(space_dim-1);
        return;
      }
      else {
        // Apply the affine upper bound.
        generalized_affine_image(var,
                                 LESS_OR_EQUAL,
                                 ub_expr,
                                 denominator);
        // Here `w != var', so that `lb_expr' is of the form
        // +/-denominator * w + b.
        const dimension_type n_w = 2*w_id;
        // Add the new constraint `var - w >= b/denominator'.
        if (w_coeff == denominator)
          if (var_id < w_id)
            add_octagonal_constraint(n_w+1, n_var+1, b, minus_den);
          else
            add_octagonal_constraint(n_var, n_w, b, minus_den);
        else {
          // Add the new constraint `var + w >= b/denominator'.
          if (var_id < w_id)
            add_octagonal_constraint(n_w, n_var+1, b, minus_den);
          else
            add_octagonal_constraint(n_var, n_w+1, b, minus_den);
        }
        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);
  PPL_DIRTY_TEMP_COEFFICIENT(minus_b);
  neg_assign_r(minus_b, b, ROUND_NOT_NEEDED);

  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 = -lb_expr;
  const Linear_Expression& sc_expr = is_sc ? lb_expr : minus_expr;

  PPL_DIRTY_TEMP(N, neg_sum);
  // Indices of the variables that are unbounded in `this->matrix'.
  PPL_UNINITIALIZED(dimension_type, neg_pinf_index);
  // Number of unbounded variables found.
  dimension_type neg_pinf_count = 0;

  // Approximate the inhomogeneous term.
  assign_r(neg_sum, minus_sc_b, ROUND_UP);

  // Approximate the homogeneous part of `sc_expr'.
  PPL_DIRTY_TEMP(N, coeff_i);
  PPL_DIRTY_TEMP(N, minus_coeff_i);
  PPL_DIRTY_TEMP(N, half);
  PPL_DIRTY_TEMP_COEFFICIENT(minus_sc_i);
  // Note: indices above `w' can be disregarded, as they all have
  // a zero coefficient in `sc_expr'.
  for (Row_iterator m_iter = m_begin, m_iter_end = m_iter + (2*w_id) + 2;
       m_iter != m_iter_end; ) {
    const dimension_type n_i = m_iter.index();
    const dimension_type id = n_i/2;
    Row_reference m_i = *m_iter;
    ++m_iter;
    Row_reference m_ci = *m_iter;
    ++m_iter;
    const Coefficient& sc_i = sc_expr.coefficient(Variable(id));
    const int sign_i = sgn(sc_i);
    if (sign_i > 0) {
      assign_r(coeff_i, sc_i, ROUND_UP);
      // Approximating `-sc_expr'.
      if (neg_pinf_count <= 1) {
        const N& double_up_approx_minus_i = m_i[n_i+1];
        if (!is_plus_infinity(double_up_approx_minus_i)) {
          // Let half = double_up_approx_minus_i / 2.
          div2exp_assign_r(half, double_up_approx_minus_i, 1, ROUND_UP);
          add_mul_assign_r(neg_sum, coeff_i, half, ROUND_UP);
        }
        else {
          ++neg_pinf_count;
          neg_pinf_index = id;
        }
      }
    }
    else if (sign_i < 0) {
      neg_assign_r(minus_sc_i, sc_i, ROUND_NOT_NEEDED);
      assign_r(minus_coeff_i, minus_sc_i, ROUND_UP);
      // Approximating `-sc_expr'.
      if (neg_pinf_count <= 1) {
        const N& double_up_approx_i = m_ci[n_i];
        if (!is_plus_infinity(double_up_approx_i)) {
          // Let half = double_up_approx_i / 2.
          div2exp_assign_r(half, double_up_approx_i, 1, ROUND_UP);
          add_mul_assign_r(neg_sum, minus_coeff_i, half, ROUND_UP);
        }
        else {
          ++neg_pinf_count;
          neg_pinf_index = id;
        }
      }
    }
  }

  // Apply the affine upper bound.
  generalized_affine_image(var,
                           LESS_OR_EQUAL,
                           ub_expr,
                           denominator);

  // Return immediately if no approximation could be computed.
  if (neg_pinf_count > 1) {
    return;
  }

  // In the following, strong closure will be definitely lost.
  reset_strongly_closed();

  // Exploit the lower approximation, if possible.
  if (neg_pinf_count <= 1) {
    // Compute quotient (if needed).
    if (sc_den != 1) {
      // 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.
      PPL_DIRTY_TEMP(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(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'.
      PPL_DIRTY_TEMP(N, double_neg_sum);
      mul2exp_assign_r(double_neg_sum, neg_sum, 1, ROUND_IGNORE);
      matrix[n_var][n_var+1] = double_neg_sum;
      // Deduce constraints of the form `-v +/- u', where `u != v'.
      deduce_minus_v_pm_u_bounds(var_id, w_id, sc_expr, sc_den, neg_sum);
    }
    else
      // Here `neg_pinf_count == 1'.
      if (neg_pinf_index != var_id) {
        const Coefficient& npi = sc_expr.coefficient(Variable(neg_pinf_index));
        if (npi == sc_den)
          // Add the constraint `v - neg_pinf_index >= -neg_sum',
          // i.e., `neg_pinf_index - v <= neg_sum'.
          if (neg_pinf_index < var_id)
            matrix[n_var][2*neg_pinf_index] = neg_sum;
          else
            matrix[2*neg_pinf_index+1][n_var+1] = neg_sum;
        else
          if (npi == minus_sc_den) {
            // Add the constraint `v + neg_pinf_index >= -neg_sum',
            // i.e., `-neg_pinf_index - v <= neg_sum'.
            if (neg_pinf_index < var_id)
              matrix[n_var][2*neg_pinf_index+1] = neg_sum;
            else
              matrix[2*neg_pinf_index][n_var+1] = neg_sum;
          }
      }
  }

  assert(OK());
}


template <typename T>
void
Octagonal_Shape<T>
::generalized_affine_preimage(const Variable var,
                              const Relation_Symbol relsym,
                              const Linear_Expression& expr,
                              Coefficient_traits::const_reference
                              denominator) {
  // 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 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 octagon.
  const dimension_type var_id = var.id();
  if (space_dim < var_id + 1)
    throw_dimension_incompatible("generalized_affine_preimage(v, r, e, d)",
                                 var.id()+1);

  // 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 an Octagonal_Shape");

  if (relsym == EQUAL) {
    // The relation symbol is "==":
    // this is just an affine preimage computation.
    affine_preimage(var, expr, denominator);
    return;
  }

  // The image of an empty octagon is empty too.
  strong_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_OR_EQUAL)
      ? GREATER_OR_EQUAL : LESS_OR_EQUAL;
    const Linear_Expression inverse
      = expr - (expr_v + denominator)*var;
    PPL_DIRTY_TEMP_COEFFICIENT(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 Octagonal_Shape by adding the constraint induced
  // by the affine relation.
  refine(var, relsym, expr, denominator);

  // If the shrunk OS is empty, its preimage is empty too; ...
  if (is_empty())
    return;
  // ...  otherwise, since the relation was not invertible,
  // we just forget all constraints on `var'.
  forget_all_octagonal_constraints(var_id);
  assert(OK());
}

template <typename T>
void
Octagonal_Shape<T>
::generalized_affine_preimage(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'.
  dimension_type lhs_space_dim = lhs.space_dimension();
  if (space_dim < lhs_space_dim)
    throw_dimension_incompatible("generalized_affine_preimage(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_preimage(e1, r, e2)",
                                 "e2", rhs);

  // Strict relation symbols are not admitted for octagons.
  if (relsym == LESS_THAN || relsym == GREATER_THAN)
    throw_generic("generalized_affine_preimage(e1, r, e2)",
                  "r is a strict relation symbol and "
                  "*this is an Octagonal_Shape");

  strong_closure_assign();
  // The image of an empty octagon is empty.
  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 all variables have a zero coefficient, then `lhs' is a constant:
  // in this case, preimage and image happen to be the same.
  if (t_lhs == 0) {
    generalized_affine_image(lhs, relsym, rhs);
    return;
  }

  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 preimages 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_OR_EQUAL)
        new_relsym = GREATER_OR_EQUAL;
      else if (relsym == GREATER_OR_EQUAL)
        new_relsym = LESS_OR_EQUAL;
    }
    Linear_Expression expr = rhs - b_lhs;
    generalized_affine_preimage(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.
      // 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 an octagonal difference,
      // it will be simply ignored. Should we compute approximations for it?
      switch (relsym) {
      case LESS_OR_EQUAL:
        refine_no_check(lhs <= rhs);
        break;
      case EQUAL:
        refine_no_check(lhs == rhs);
        break;
      case GREATER_OR_EQUAL:
        refine_no_check(lhs >= rhs);
        break;
      default:
        // We already dealt with the other cases.
        throw std::runtime_error("PPL internal error");
      }

      // Any image of an empty octagon is empty.
      if (is_empty())
        return;
      // Existentially quantify all variables in the lhs.
      for (dimension_type i = lhs_vars.size(); i-- > 0; ) {
        dimension_type lhs_vars_i = lhs_vars[i].id();
        forget_all_octagonal_constraints(lhs_vars_i);
      }
    }
    else {
      // Some variables in `lhs' also occur in `rhs'.

      // 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 refine_no_check()
      // ensures some approximation is tried even when the constraint
      // is not an octagonal difference.
      affine_image(new_var, lhs);
      // Existentially quantify all variables in the lhs.
      // NOTE: enforce strong closure for precision.
      strong_closure_assign();
      assert(!marked_empty());
      for (dimension_type i = lhs_vars.size(); i-- > 0; ) {
        dimension_type lhs_vars_i = lhs_vars[i].id();
        forget_all_octagonal_constraints(lhs_vars_i);
      }
      // Constrain the new dimension so that it is related to
      // the left hand side as dictated by `relsym'.
      // Note: if `rhs == v + b_rhs' or `rhs == -v + b_rhs' or `rhs == b_rhs',
      // one of the following constraints will be added, because they
      // are octagonal differences.
      // Else the following constraints are NOT octagonal differences,
      // so the method refine_no_check() will ignore them.
      switch (relsym) {
      case LESS_OR_EQUAL:
        refine_no_check(new_var <= rhs);
        break;
      case EQUAL:
        refine_no_check(new_var == rhs);
        break;
      case GREATER_OR_EQUAL:
        refine_no_check(new_var >= rhs);
        break;
      default:
        // We already dealt with the other cases.
        throw std::runtime_error("PPL internal error");
      }
      // Remove the temporarily added dimension.
      remove_higher_space_dimensions(space_dim-1);
    }
  }
  assert(OK());
}

template <typename T>
void
Octagonal_Shape<T>::bounded_affine_preimage(const Variable var,
                                            const Linear_Expression& lb_expr,
                                            const Linear_Expression& ub_expr,
                                            Coefficient_traits::const_reference
                                            denominator) {
  // The denominator cannot be zero.
  if (denominator == 0)
    throw_generic("bounded_affine_preimage(v, lb, ub, d)", "d == 0");

  // `var' should be one of the dimensions of the octagon.
  const dimension_type var_id = var.id();
  if (space_dim < var_id + 1)
    throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub, d)",
                                 var.id()+1);

  // The dimension of `lb_expr' and `ub_expr' should not be
  // greater than the dimension of `*this'.
  const dimension_type lb_space_dim = lb_expr.space_dimension();
  if (space_dim < lb_space_dim)
    throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub)",
                                 "lb", lb_expr);
  const dimension_type ub_space_dim = ub_expr.space_dimension();
  if (space_dim < ub_space_dim)
    throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub)",
                                 "ub", ub_expr);

  strong_closure_assign();
  // The image of an empty octagon is empty too.
  if (marked_empty())
    return;

  if (ub_expr.coefficient(var) == 0) {
    refine(var, LESS_OR_EQUAL, ub_expr, denominator);
    generalized_affine_preimage(var, GREATER_OR_EQUAL,
                                lb_expr, denominator);
    return;
  }
  if (lb_expr.coefficient(var) == 0) {
    refine(var, GREATER_OR_EQUAL, lb_expr, denominator);
    generalized_affine_preimage(var, LESS_OR_EQUAL,
                                ub_expr, denominator);
    return;
  }

  const Coefficient& expr_v = lb_expr.coefficient(var);
  // Here `var' occurs in `lb_expr' and `ub_expr'.
  // To ease the computation, we add an additional dimension.
  const Variable new_var = Variable(space_dim);
  add_space_dimensions_and_embed(1);
  const Linear_Expression lb_inverse
    = lb_expr - (expr_v + denominator)*var;
  PPL_DIRTY_TEMP_COEFFICIENT(inverse_den);
  neg_assign(inverse_den, expr_v);
  affine_image(new_var, lb_inverse, inverse_den);
  strong_closure_assign();
  assert(!marked_empty());
  generalized_affine_preimage(var, LESS_OR_EQUAL,
                              ub_expr, denominator);
  if (sgn(denominator) == sgn(inverse_den))
    refine_no_check(var >= new_var) ;
  else
    refine_no_check(var <= new_var);
  // Remove the temporarily added dimension.
  remove_higher_space_dimensions(space_dim-1);
}

template <typename T>
Constraint_System
Octagonal_Shape<T>::constraints() const {
  Constraint_System cs;
  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);

    typedef typename OR_Matrix<N>::const_row_iterator Row_Iterator;
    typedef typename OR_Matrix<N>::const_row_reference_type Row_Reference;

    Row_Iterator m_begin = matrix.row_begin();
    Row_Iterator m_end = matrix.row_end();

    PPL_DIRTY_TEMP_COEFFICIENT(a);
    PPL_DIRTY_TEMP_COEFFICIENT(b);

    // Go through all the unary constraints in `matrix'.
    for (Row_Iterator i_iter = m_begin; i_iter != m_end; ) {
      const dimension_type i = i_iter.index();
      const Variable x(i/2);
      const N& c_i_ii = (*i_iter)[i+1];
      ++i_iter;
      const N& c_ii_i = (*i_iter)[i];
      ++i_iter;
      // Go through unary constraints.
      if (is_additive_inverse(c_i_ii, c_ii_i)) {
        // We have a unary equality constraint.
        numer_denom(c_ii_i, b, a);
        a *= 2;
        cs.insert(a*x == b);
      }
      else {
        // We have 0, 1 or 2 inequality constraints.
        if (!is_plus_infinity(c_i_ii)) {
          numer_denom(c_i_ii, b, a);
          a *= 2;
          cs.insert(-a*x <= b);
        }
        if (!is_plus_infinity(c_ii_i)) {
          numer_denom(c_ii_i, b, a);
          a *= 2;
          cs.insert(a*x <= b);
        }
      }
    }
    //  Go through all the binary constraints in `matrix'.
    for (Row_Iterator i_iter = m_begin; i_iter != m_end; ) {
      const dimension_type i = i_iter.index();
      Row_Reference r_i = *i_iter;
      ++i_iter;
      Row_Reference r_ii = *i_iter;
      ++i_iter;
      const Variable y(i/2);
      for (dimension_type j = 0; j < i; j += 2) {
        const N& c_i_j = r_i[j];
        const N& c_ii_jj = r_ii[j+1];
        const Variable x(j/2);
        if (is_additive_inverse(c_ii_jj, c_i_j)) {
          // We have an equality constraint of the form ax - ay = b.
          numer_denom(c_i_j, b, a);
          cs.insert(a*x - a*y == b);
        }
        else {
          // We have 0, 1 or 2 inequality constraints.
          if (!is_plus_infinity(c_i_j)) {
            numer_denom(c_i_j, b, a);
            cs.insert(a*x - a*y <= b);
          }
          if (!is_plus_infinity(c_ii_jj)) {
            numer_denom(c_ii_jj, b, a);
            cs.insert(a*y - a*x <= b);
          }
        }

        const N& c_ii_j = r_ii[j];
        const N& c_i_jj = r_i[j+1];
        if (is_additive_inverse(c_i_jj, c_ii_j)) {
          // We have an equality constraint of the form ax + ay = b.
          numer_denom(c_ii_j, b, a);
          cs.insert(a*x + a*y == b);
        }
        else {
          // We have 0, 1 or 2 inequality constraints.
          if (!is_plus_infinity(c_i_jj)) {
            numer_denom(c_i_jj, b, a);
            cs.insert(-a*x - a*y <= b);
          }
          if (!is_plus_infinity(c_ii_j)) {
            numer_denom(c_ii_j, b, a);
            cs.insert(a*x + a*y <= b);
          }
        }
      }
    }
  }
  return cs;
}

template <typename T>
void
Octagonal_Shape<T>::expand_space_dimension(Variable var, dimension_type m) {
  // `var' should be one of the dimensions of the vector space.
  const dimension_type var_id = var.id();
  if (var_id+1 > space_dim)
    throw_dimension_incompatible("expand_space_dimension(v, m)", var_id+1);

  // The space dimension of the resulting octagon should not
  // overflow the maximum allowed space dimension.
  if (m > max_space_dimension() - space_dim)
    throw_generic("expand_dimension(v, m)",
                  "adding m new space dimensions exceeds "
                  "the maximum allowed space dimension");

  // Nothing to do, if no dimensions must be added.
  if (m == 0)
    return;

  // Keep track of the dimension before adding the new ones.
  const dimension_type old_num_rows = matrix.num_rows();

  // Add the required new dimensions.
  add_space_dimensions_and_embed(m);

  // For each constraints involving variable `var', we add a
  // similar constraint with the new variable substituted for
  // variable `var'.
  typedef typename OR_Matrix<N>::row_iterator Row_Iterator;
  typedef typename OR_Matrix<N>::row_reference_type Row_Reference;
  typedef typename OR_Matrix<N>::const_row_iterator Row_iterator;
  typedef typename OR_Matrix<N>::const_row_reference_type Row_reference;

  const Row_Iterator m_begin = matrix.row_begin();
  const Row_Iterator m_end = matrix.row_end();
  const dimension_type n_var = 2*var_id;
  Row_iterator v_iter = m_begin + n_var;
  Row_reference m_v = *v_iter;
  Row_reference m_cv = *(v_iter+1);

  for (Row_Iterator i_iter = m_begin + old_num_rows; i_iter != m_end;
       i_iter += 2) {
    Row_Reference m_i = *i_iter;
    Row_Reference m_ci = *(i_iter+1);
    const dimension_type i = i_iter.index();
    const dimension_type ci = i+1;
    m_i[ci] = m_v[n_var+1];
    m_ci[i] = m_cv[n_var];
    for (dimension_type j = 0; j < n_var; ++j) {
      m_i[j] = m_v[j];
      m_ci[j] = m_cv[j];
    }
    for (dimension_type j = n_var+2; j < old_num_rows; ++j) {
      Row_Iterator j_iter = m_begin + j;
      Row_Reference m_cj = (j % 2 != 0) ? *(j_iter-1) : *(j_iter+1);
      m_i[j] = m_cj[n_var+1];
      m_ci[j] = m_cj[n_var];
    }
  }
  // In general, adding a constraint does not preserve the strong closure
  // of the octagon.
  if (marked_strongly_closed())
    reset_strongly_closed();
  assert(OK());
}

template <typename T>
void
Octagonal_Shape<T>::fold_space_dimensions(const Variables_Set& to_be_folded,
                                          Variable var) {
  // `var' should be one of the dimensions of the octagon.
  if (var.space_dimension() > space_dim)
    throw_dimension_incompatible("fold_space_dimensions(tbf, v)", "v", var);

  // The folding of no dimensions is a no-op.
  if (to_be_folded.empty())
    return;

  // All variables in `to_be_folded' should be dimensions of the octagon.
  if (to_be_folded.space_dimension() > space_dim)
    throw_dimension_incompatible("fold_space_dimensions(tbf, ...)",
                                 to_be_folded.space_dimension());

  // Moreover, `var.id()' should not occur in `to_be_folded'.
  if (to_be_folded.find(var.id()) != to_be_folded.end())
    throw_generic("fold_space_dimensions(tbf, v)",
                  "v should not occur in tbf");

  // Recompute the elements of the row and the column corresponding
  // to variable `var' by taking the join of their value with the
  // value of the corresponding elements in the row and column of the
  // variable `to_be_folded'.
  typedef typename OR_Matrix<N>::row_iterator Row_Iterator;
  typedef typename OR_Matrix<N>::row_reference_type Row_Reference;

  const Row_Iterator m_begin = matrix.row_begin();

  strong_closure_assign();
  const dimension_type n_rows = matrix.num_rows();
  const dimension_type n_var = 2*var.id();
  Row_Iterator v_iter = m_begin + n_var;
  Row_Reference m_v = *v_iter;
  Row_Reference m_cv = *(v_iter+1);
  for (Variables_Set::const_iterator i = to_be_folded.begin(),
         tbf_end = to_be_folded.end(); i != tbf_end; ++i) {
    const dimension_type tbf_id = *i;
    const dimension_type tbf_var = 2*tbf_id;
    Row_Iterator tbf_iter = m_begin + tbf_var;
    Row_Reference m_tbf = *tbf_iter;
    Row_Reference m_ctbf = *(tbf_iter+1);
    max_assign(m_v[n_var+1], m_tbf[tbf_var+1]);
    max_assign(m_cv[n_var], m_ctbf[tbf_var]);

    const dimension_type min_id = std::min(n_var, tbf_var);
    const dimension_type max_id = std::max(n_var, tbf_var);

    for (dimension_type j = 0; j < min_id; ++j) {
      const dimension_type cj = coherent_index(j);
      max_assign(m_v[j], m_tbf[j]);
      max_assign(m_cv[j], m_ctbf[j]);
      max_assign(m_cv[cj], m_ctbf[cj]);
      max_assign(m_v[cj], m_tbf[cj]);
    }
    for (dimension_type j = min_id+2; j < max_id; ++j) {
      const dimension_type cj = coherent_index(j);
      Row_Iterator j_iter = m_begin + j;
      Row_Reference m_j = *j_iter;
      Row_Reference m_cj = (j % 2 != 0) ? *(j_iter-1) : *(j_iter+1);
      if (n_var == min_id) {
        max_assign(m_cj[n_var+1], m_tbf[j]);
        max_assign(m_cj[n_var], m_ctbf[j]);
        max_assign(m_j[n_var], m_ctbf[cj]);
        max_assign(m_j[n_var+1], m_tbf[cj]);
      }
      else {
        max_assign(m_v[j], m_cj[tbf_var+1]);
        max_assign(m_cv[j], m_cj[tbf_var]);
        max_assign(m_cv[cj], m_j[tbf_var]);
        max_assign(m_v[cj], m_j[tbf_var+1]);
      }
    }
    for (dimension_type j = max_id+2; j < n_rows; ++j) {
      Row_Iterator j_iter = m_begin + j;
      Row_Reference m_j = *j_iter;
      Row_Reference m_cj = (j % 2 != 0) ? *(j_iter-1) : *(j_iter+1);
      max_assign(m_cj[n_var+1], m_cj[tbf_var+1]);
      max_assign(m_cj[n_var], m_cj[tbf_var]);
      max_assign(m_j[n_var], m_j[tbf_var]);
      max_assign(m_j[n_var+1], m_j[tbf_var+1]);
    }
  }
  remove_space_dimensions(to_be_folded);
}

template <typename T>
bool
Octagonal_Shape<T>
::BHZ09_upper_bound_assign_if_exact(const Octagonal_Shape& y) {
  // Declare a const reference to *this (to avoid accidental modifications).
  const Octagonal_Shape& x = *this;
  const dimension_type x_space_dim = x.space_dimension();

  // Private method: the caller must ensure the following.
  assert(x_space_dim == y.space_dimension());

  // The zero-dim case is trivial.
  if (x_space_dim == 0) {
    upper_bound_assign(y);
    return true;
  }
  // If `x' or `y' is (known to be) empty, the upper bound is exact.
  if (x.marked_empty()) {
    *this = y;
    return true;
  }
  else if (y.is_empty())
    return true;
  else if (x.is_empty()) {
    *this = y;
    return true;
  }

  // Here both `x' and `y' are known to be non-empty.
  assert(x.marked_strongly_closed());
  assert(y.marked_strongly_closed());
  // Pre-compute the upper bound of `x' and `y'.
  Octagonal_Shape<T> ub(x);
  ub.upper_bound_assign(y);

  // Compute redundancy information for x and y.
  // TODO: provide a nicer data structure for redundancy.
  std::vector<Bit_Row> x_non_red;
  x.non_redundant_matrix_entries(x_non_red);
  std::vector<Bit_Row> y_non_red;
  y.non_redundant_matrix_entries(y_non_red);

  PPL_DIRTY_TEMP(N, lhs);
  PPL_DIRTY_TEMP(N, lhs_copy);
  PPL_DIRTY_TEMP(N, rhs);
  PPL_DIRTY_TEMP(N, temp_zero);
  assign_r(temp_zero, 0, ROUND_NOT_NEEDED);

  typedef typename OR_Matrix<N>::const_row_iterator Row_Iterator;
  typedef typename OR_Matrix<N>::const_row_reference_type Row_Reference;
  const dimension_type n_rows = x.matrix.num_rows();
  const Row_Iterator x_m_begin = x.matrix.row_begin();
  const Row_Iterator y_m_begin = y.matrix.row_begin();
  const Row_Iterator ub_m_begin = ub.matrix.row_begin();

  for (dimension_type i = n_rows; i-- > 0; ) {
    const Bit_Row& x_non_red_i = x_non_red[i];
    const dimension_type ci = coherent_index(i);
    const dimension_type row_size_i = OR_Matrix<N>::row_size(i);
    Row_Reference x_i = *(x_m_begin + i);
    Row_Reference y_i = *(y_m_begin + i);
    Row_Reference ub_i = *(ub_m_begin + i);
    const N& ub_i_ci = ub_i[ci];
    for (dimension_type j = row_size_i; j-- > 0; ) {
      // Check redundancy of x_i_j.
      if (!x_non_red_i[j])
        continue;
      const N& x_i_j = x_i[j];
      // Check 1st condition in BHZ09 theorem.
      if (x_i_j >= y_i[j])
        continue;
      const dimension_type cj = coherent_index(j);
      const dimension_type row_size_cj = OR_Matrix<N>::row_size(cj);
      Row_Reference ub_cj = *(ub_m_begin + cj);
      const N& ub_cj_j = ub_cj[j];
      for (dimension_type k = 0; k < n_rows; ++k) {
        const Bit_Row& y_non_red_k = y_non_red[k];
        const dimension_type ck = coherent_index(k);
        const dimension_type row_size_k = OR_Matrix<N>::row_size(k);
        Row_Reference x_k = *(x_m_begin + k);
        Row_Reference y_k = *(y_m_begin + k);
        Row_Reference ub_k = *(ub_m_begin + k);
        const N& ub_k_ck = ub_k[ck];
        // Be careful: for each index h, the diagonal element m[h][h]
        // is (by convention) +infty in our implementation; however,
        // BHZ09 theorem assumes that it is equal to 0.
        const N& ub_k_j = (k == j) ? temp_zero
          : (j < row_size_k ? ub_k[j] : ub_cj[ck]);
        const N& ub_i_ck = (i == ck) ? temp_zero
          : (ck < row_size_i ? ub_i[ck] : ub_k[ci]);

        for (dimension_type ell = row_size_k; ell-- > 0; ) {
          // Check redundancy of y_k_ell.
          if (!y_non_red_k[ell])
            continue;
          const N& y_k_ell = y_k[ell];
          // Check 2nd condition in BHZ09 theorem.
          if (y_k_ell >= x_k[ell])
            continue;
          const dimension_type cell = coherent_index(ell);
          Row_Reference ub_cell = *(ub_m_begin + cell);
          const N& ub_i_ell = (i == ell) ? temp_zero
            : (ell < row_size_i ? ub_i[ell] : ub_cell[ci]);
          const N& ub_cj_ell = (cj == ell) ? temp_zero
            : (ell < row_size_cj ? ub_cj[ell] : ub_cell[j]);
          // Check 3rd condition in BHZ09 theorem.
          add_assign_r(lhs, x_i_j, y_k_ell, ROUND_UP);
          add_assign_r(rhs, ub_i_ell, ub_k_j, ROUND_UP);
          if (lhs >= rhs)
            continue;
          // Check 4th condition in BHZ09 theorem.
          add_assign_r(rhs, ub_i_ck, ub_cj_ell, ROUND_UP);
          if (lhs >= rhs)
            continue;
          // Check 5th condition in BHZ09 theorem.
          assign_r(lhs_copy, lhs, ROUND_NOT_NEEDED);
          add_assign_r(lhs, lhs_copy, x_i_j, ROUND_UP);
          add_assign_r(rhs, ub_i_ell, ub_i_ck, ROUND_UP);
          add_assign_r(rhs, rhs, ub_cj_j, ROUND_UP);
          if (lhs >= rhs)
            continue;
          // Check 6th condition in BHZ09 theorem.
          add_assign_r(rhs, ub_k_j, ub_cj_ell, ROUND_UP);
          add_assign_r(rhs, rhs, ub_i_ci, ROUND_UP);
          if (lhs >= rhs)
            continue;
          // Check 7th condition of BHZ09 theorem.
          add_assign_r(lhs, lhs_copy, y_k_ell, ROUND_UP);
          add_assign_r(rhs, ub_i_ell, ub_cj_ell, ROUND_UP);
          add_assign_r(rhs, rhs, ub_k_ck, ROUND_UP);
          if (lhs >= rhs)
            continue;
          // Check 8th (last) condition in BHZ09 theorem.
          add_assign_r(rhs, ub_k_j, ub_i_ck, ROUND_UP);
          add_assign_r(rhs, rhs, ub_cell[ell], ROUND_UP);
          if (lhs < rhs)
            // All 8 conditions are satisfied:
            // upper bound is not exact.
            return false;
        }
      }
    }
  }

  // The upper bound of x and y is indeed exact.
  swap(ub);
  assert(OK());
  return true;
}

/*! \relates Parma_Polyhedra_Library::Octagonal_Shape */
template <typename T>
std::ostream&
IO_Operators::operator<<(std::ostream& s, const Octagonal_Shape<T>& x) {
  // Handle special cases first.
  if (x.marked_empty()) {
    s << "false";
    return s;
  }
  if (x.is_universe()) {
    s << "true";
    return s;
  }

  typedef typename Octagonal_Shape<T>::coefficient_type N;
  typedef typename OR_Matrix<N>::const_row_iterator Row_Iterator;
  typedef typename OR_Matrix<N>::const_row_reference_type Row_Reference;

  // Records whether or not we still have to print the first constraint.
  bool first = true;

  Row_Iterator m_begin = x.matrix.row_begin();
  Row_Iterator m_end = x.matrix.row_end();

  // Temporaries.
  PPL_DIRTY_TEMP(N, negation);
  PPL_DIRTY_TEMP(N, half);
  // Go through all the unary constraints.
  // (Note: loop iterator is incremented in the loop body.)
  for (Row_Iterator i_iter = m_begin; i_iter != m_end; ) {
    const dimension_type i = i_iter.index();
    const Variable v_i = Variable(i/2);
    const N& x_i_ii = (*i_iter)[i+1];
    ++i_iter;
    const N& x_ii_i = (*i_iter)[i];
    ++i_iter;
    // Check whether or not it is an equality constraint.
    if (is_additive_inverse(x_i_ii, x_ii_i)) {
      // It is an equality.
      assert(!is_plus_infinity(x_i_ii) && !is_plus_infinity(x_ii_i));
      if (first)
        first = false;
      else
        s << ", ";
      // If the value bound can NOT be divided by 2 exactly,
      // then we output the constraint `2*v_i == bound'.
      if (div2exp_assign_r(half, x_ii_i, 1, ROUND_UP) == V_EQ)
        s << v_i << " == " << half;
      else
        s << "2*" << v_i << " == " << x_ii_i;
    }
    else {
      // We will print unary non-strict inequalities, if any.
      if (!is_plus_infinity(x_i_ii)) {
        if (first)
          first = false;
        else
          s << ", ";
        neg_assign_r(negation, x_i_ii, ROUND_NOT_NEEDED);
        // If the value bound can NOT be divided by 2 exactly,
        // then we output the constraint `2*v_i >= negation'.
        if (div2exp_assign_r(half, negation, 1, ROUND_UP) == V_EQ)
          s << v_i << " >= " << half;
        else
          s << "2*" << v_i << " >= " << negation;
      }
      if (!is_plus_infinity(x_ii_i)) {
        if (first)
          first = false;
        else
          s << ", ";
        // If the value bound can NOT be divided by 2 exactly,
        // then we output the constraint `2*v_i <= bound'.
        if (div2exp_assign_r(half, x_ii_i, 1, ROUND_UP) == V_EQ)
          s << v_i << " <= " << half;
        else
          s << "2*" << v_i << " <= " << x_ii_i;
      }
    }
  }

  // Go through all the binary constraints.
  // (Note: loop iterator is incremented in the loop body.)
  for (Row_Iterator i_iter = m_begin; i_iter != m_end; ) {
    const dimension_type i = i_iter.index();
    const Variable v_i = Variable(i/2);
    Row_Reference r_i = *i_iter;
    ++i_iter;
    Row_Reference r_ii = *i_iter;
    ++i_iter;

    for (dimension_type j = 0; j < i; j += 2) {
      const Variable v_j = Variable(j/2);
      // Print binary differences.
      const N& x_ii_jj = r_ii[j+1];
      const N& x_i_j = r_i[j];
      // Check whether or not it is an equality constraint.
      if (is_additive_inverse(x_ii_jj, x_i_j)) {
        // It is an equality.
        assert(!is_plus_infinity(x_i_j) && !is_plus_infinity(x_ii_jj));
        if (first)
          first = false;
        else
          s << ", ";
        if (sgn(x_i_j) >= 0)
          s << v_j << " - " << v_i << " == " << x_i_j;
        else
          s << v_i << " - " << v_j << " == " << x_ii_jj;
      }
      else {
        // We will print non-strict inequalities, if any.
        if (!is_plus_infinity(x_i_j)) {
          if (first)
            first = false;
          else
            s << ", ";
          if (sgn(x_i_j) >= 0)
            s << v_j << " - " << v_i << " <= " << x_i_j;
          else {
            neg_assign_r(negation, x_i_j, ROUND_DOWN);
            s << v_i << " - " << v_j << " >= " << negation;
          }
        }
        if (!is_plus_infinity(x_ii_jj)) {
          if (first)
            first = false;
          else
            s << ", ";
          if (sgn(x_ii_jj) >= 0)
            s << v_i << " - " << v_j << " <= " << x_ii_jj;
          else {
            neg_assign_r(negation, x_ii_jj, ROUND_DOWN);
            s << v_j << " - " << v_i << " >= " << negation;
          }
        }
      }
      // Print binary sums.
      const N& x_i_jj = r_i[j+1];
      const N& x_ii_j = r_ii[j];
      // Check whether or not it is an equality constraint.
      if (is_additive_inverse(x_i_jj, x_ii_j)) {
        // It is an equality.
        assert(!is_plus_infinity(x_i_jj) && !is_plus_infinity(x_ii_j));
        if (first)
          first = false;
        else
          s << ", ";
        s << v_j << " + " << v_i << " == " << x_ii_j;
      }
      else {
        // We will print non-strict inequalities, if any.
        if (!is_plus_infinity(x_i_jj)) {
          if (first)
            first = false;
          else
            s << ", ";
          neg_assign_r(negation, x_i_jj, ROUND_DOWN);
          s << v_j << " + " << v_i << " >= " << negation;
        }
        if (!is_plus_infinity(x_ii_j)) {
          if (first)
            first = false;
          else
            s << ", ";
          s << v_j << " + " << v_i << " <= " << x_ii_j;
        }
      }
    }
  }
  return s;
}

template <typename T>
void
Octagonal_Shape<T>::ascii_dump(std::ostream& s) const {
  s << "space_dim "
    << space_dim
    << "\n";
  status.ascii_dump(s);
  s << "\n";
  matrix.ascii_dump(s);
}

PPL_OUTPUT_TEMPLATE_DEFINITIONS(T, Octagonal_Shape<T>)

template <typename T>
bool
Octagonal_Shape<T>::ascii_load(std::istream& s) {
  std::string str;

  if (!(s >> str) || str != "space_dim")
    return false;

  if (!(s >> space_dim))
    return false;

  if (!status.ascii_load(s))
    return false;

  if (!matrix.ascii_load(s))
    return false;

  assert(OK());
  return true;
}

template <typename T>
memory_size_type
Octagonal_Shape<T>::external_memory_in_bytes() const {
  return matrix.external_memory_in_bytes();
}

template <typename T>
bool
Octagonal_Shape<T>::OK() const {
  // Check whether the matrix is well-formed.
  if (!matrix.OK())
    return false;

  // Check whether the status information is legal.
  if (!status.OK())
    return false;

  // All empty octagons are OK.
  if (marked_empty())
    return true;

  // 0-dim universe octagon is OK.
  if (space_dim == 0)
    return true;

  // MINUS_INFINITY cannot occur at all.
  for (typename OR_Matrix<N>::const_row_iterator i = matrix.row_begin(),
         matrix_row_end = matrix.row_end(); i != matrix_row_end; ++i) {
    typename OR_Matrix<N>::const_row_reference_type x_i = *i;
    for (dimension_type j = i.row_size(); j-- > 0; )
      if (is_minus_infinity(x_i[j])) {
#ifndef NDEBUG
        using namespace Parma_Polyhedra_Library::IO_Operators;
        std::cerr << "Octagonal_Shape::"
                  << "matrix[" << i.index() << "][" << j << "] = "
                  << x_i[j] << "!"
                  << std::endl;
#endif
        return false;
      }
  }

  // On the main diagonal only PLUS_INFINITY can occur.
  for (typename OR_Matrix<N>::const_row_iterator i = matrix.row_begin(),
         m_end = matrix.row_end(); i != m_end; ++i) {
    typename OR_Matrix<N>::const_row_reference_type r = *i;
    const N& m_i_i = r[i.index()];
    if (!is_plus_infinity(m_i_i)) {
#ifndef NDEBUG
      const dimension_type j = i.index();
      using namespace Parma_Polyhedra_Library::IO_Operators;
      std::cerr << "Octagonal_Shape::matrix[" << j << "][" << j << "] = "
                << m_i_i << "!  (+inf was expected.)\n";
#endif
      return false;
    }
  }

  // The following tests might result in false alarms when using floating
  // point coefficients: they are only meaningful if the coefficient type
  // base is exact (since otherwise strong closure is approximated).
  if (std::numeric_limits<coefficient_type_base>::is_exact) {

    // Check whether the closure information is legal.
    if (marked_strongly_closed()) {
      Octagonal_Shape x = *this;
      x.reset_strongly_closed();
      x.strong_closure_assign();
      if (x.matrix != matrix) {
#ifndef NDEBUG
        std::cerr << "Octagonal_Shape is marked as strongly closed "
                  << "but it is not!\n";
#endif
        return false;
      }
    }

    // A closed octagon must be strong-coherent.
    if (marked_strongly_closed())
      if (!is_strong_coherent()) {
#ifndef NDEBUG
        std::cerr << "Octagonal_Shape is not strong-coherent!\n";
#endif
        return false;
      }
  }

  // All checks passed.
  return true;
}


template <typename T>
void
Octagonal_Shape<T>
::throw_dimension_incompatible(const char* method,
                               const Octagonal_Shape& y) const {
  std::ostringstream s;
  s << "PPL::Octagonal_Shape::" << method << ":\n"
    << "this->space_dimension() == " << space_dimension()
    << ", y->space_dimension() == " << y.space_dimension() << ".";
  throw std::invalid_argument(s.str());
}

template <typename T>
void
Octagonal_Shape<T>
::throw_dimension_incompatible(const char* method,
                               dimension_type required_dim) const {
  std::ostringstream s;
  s << "PPL::Octagonal_Shape::" << method << ":\n"
    << "this->space_dimension() == " << space_dimension()
    << ", required dimension == " << required_dim << ".";
  throw std::invalid_argument(s.str());
}

template <typename T>
void
Octagonal_Shape<T>::throw_dimension_incompatible(const char* method,
                                                 const Constraint& c) const {
  std::ostringstream s;
  s << "PPL::Octagonal_Shape::" << method << ":\n"
    << "this->space_dimension() == " << space_dimension()
    << ", c->space_dimension == " << c.space_dimension() << ".";
  throw std::invalid_argument(s.str());
}

template <typename T>
void
Octagonal_Shape<T>::throw_dimension_incompatible(const char* method,
                                                 const Congruence& cg) const {
  std::ostringstream s;
  s << "PPL::Octagonal_Shape::" << method << ":\n"
    << "this->space_dimension() == " << space_dimension()
    << ", cg->space_dimension == " << cg.space_dimension() << ".";
  throw std::invalid_argument(s.str());
}

template <typename T>
void
Octagonal_Shape<T>::throw_dimension_incompatible(const char* method,
                                                 const Generator& g) const {
  std::ostringstream s;
  s << "PPL::Octagonal_Shape::" << method << ":\n"
    << "this->space_dimension() == " << space_dimension()
    << ", g->space_dimension == " << g.space_dimension() << ".";
  throw std::invalid_argument(s.str());
}

template <typename T>
void
Octagonal_Shape<T>::throw_constraint_incompatible(const char* method) const {
  std::ostringstream s;
  s << "PPL::Octagonal_Shape::" << method << ":\n"
    << "the constraint is incompatible.";
  throw std::invalid_argument(s.str());
}

template <typename T>
void
Octagonal_Shape<T>
::throw_expression_too_complex(const char* method,
                               const Linear_Expression& e) const {
  using namespace IO_Operators;
  std::ostringstream s;
  s << "PPL::Octagonal_Shape::" << method << ":\n"
    << e << " is too complex.";
  throw std::invalid_argument(s.str());
}

template <typename T>
void
Octagonal_Shape<T>
::throw_dimension_incompatible(const char* method,
                               const char* name_row,
                               const Linear_Expression& y) const {
  std::ostringstream s;
  s << "PPL::Octagonal_Shape::" << method << ":\n"
    << "this->space_dimension() == " << space_dimension()
    << ", " << name_row << "->space_dimension() == "
    << y.space_dimension() << ".";
  throw std::invalid_argument(s.str());
}


template <typename T>
void
Octagonal_Shape<T>::throw_generic(const char* method,
                                  const char* reason) const {
  std::ostringstream s;
  s << "PPL::Octagonal_Shape::" << method << ":\n"
    << reason << ".";
  throw std::invalid_argument(s.str());
}

} // namespace Parma_Polyhedra_Library

/* Automatically generated from PPL source file ../src/Octagonal_Shape.defs.hh line 2015. */

/* Automatically generated from PPL source file ../src/BD_Shape.inlines.hh line 34. */
#include <cassert>
#include <vector>
#include <iostream>
#include <algorithm>

namespace Parma_Polyhedra_Library {

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_zero_dim_univ() const {
  return status.test_zero_dim_univ();
}

template <typename T>
inline bool
BD_Shape<T>::marked_empty() const {
  return status.test_empty();
}

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 void
BD_Shape<T>::set_zero_dim_univ() {
  status.set_zero_dim_univ();
}

template <typename T>
inline void
BD_Shape<T>::set_empty() {
  status.set_empty();
}

template <typename T>
inline void
BD_Shape<T>::set_shortest_path_closed() {
  status.set_shortest_path_closed();
}

template <typename T>
inline void
BD_Shape<T>::set_shortest_path_reduced() {
  status.set_shortest_path_reduced();
}

template <typename T>
inline void
BD_Shape<T>::reset_shortest_path_closed() {
  status.reset_shortest_path_closed();
}

template <typename T>
inline void
BD_Shape<T>::reset_shortest_path_reduced() {
  status.reset_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.
      set_shortest_path_closed();
  }
  assert(OK());
}

template <typename T>
inline
BD_Shape<T>::BD_Shape(const BD_Shape& y, Complexity_Class)
  : 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, Complexity_Class)
  // For maximum precision, enforce shortest-path closure
  // before copying the DB matrix.
  : dbm((y.shortest_path_closure_assign(), y.dbm)),
    status(),
    redundancy_dbm() {
  // TODO: handle flags properly, possibly taking special cases into account.
  if (y.marked_empty())
    set_empty();
  else if (y.marked_zero_dim_univ())
    set_zero_dim_univ();
}

template <typename T>
inline Congruence_System
BD_Shape<T>::congruences() const {
  return minimized_congruences();
}

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 bool
BD_Shape<T>::add_congruence_and_minimize(const Congruence& cg) {
  add_congruence(cg);
  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(),
	 cs_end = cs.end(); i != cs_end; ++i)
    add_constraint(*i);
}

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 void
BD_Shape<T>::add_recycled_constraints(Constraint_System& cs) {
  add_constraints(cs);
}

template <typename T>
inline bool
BD_Shape<T>::add_recycled_constraints_and_minimize(Constraint_System& cs) {
  return add_constraints_and_minimize(cs);
}

template <typename T>
inline void
BD_Shape<T>::add_congruences(const Congruence_System& cgs) {
  for (Congruence_System::const_iterator i = cgs.begin(),
	 cgs_end = cgs.end(); i != cgs_end; ++i)
    add_congruence(*i);
}

template <typename T>
inline bool
BD_Shape<T>::add_congruences_and_minimize(const Congruence_System& cgs) {
  add_congruences(cgs);
  return !is_empty();
}

template <typename T>
inline void
BD_Shape<T>::add_recycled_congruences(Congruence_System& cgs) {
  add_congruences(cgs);
}

template <typename T>
inline bool
BD_Shape<T>::add_recycled_congruences_and_minimize(Congruence_System& cgs) {
  return add_congruences_and_minimize(cgs);
}

template <typename T>
inline void
BD_Shape<T>::refine_with_constraint(const Constraint& c) {
  const dimension_type c_space_dim = c.space_dimension();
  // Dimension-compatibility check.
  if (c_space_dim > space_dimension())
    throw_dimension_incompatible("refine_with_constraint(c)", c);

  if (!marked_empty())
    refine_no_check(c);
}

template <typename T>
inline void
BD_Shape<T>::refine_with_constraints(const Constraint_System& cs) {
  // Dimension-compatibility check.
  if (cs.space_dimension() > space_dimension())
    throw_generic("refine_with_constraints(cs)",
                  "cs and *this are space-dimension incompatible");

  for (Constraint_System::const_iterator i = cs.begin(),
	 cs_end = cs.end(); !marked_empty() && i != cs_end; ++i)
    refine_no_check(*i);
}

template <typename T>
inline void
BD_Shape<T>::refine_with_congruence(const Congruence& cg) {
  const dimension_type cg_space_dim = cg.space_dimension();
  // Dimension-compatibility check.
  if (cg_space_dim > space_dimension())
    throw_dimension_incompatible("refine_with_congruence(cg)", cg);

  if (!marked_empty())
    refine_no_check(cg);
}

template <typename T>
void
BD_Shape<T>::refine_with_congruences(const Congruence_System& cgs) {
  // Dimension-compatibility check.
  if (cgs.space_dimension() > space_dimension())
    throw_generic("refine_with_congruences(cgs)",
                  "cgs and *this are space-dimension incompatible");

  for (Congruence_System::const_iterator i = cgs.begin(),
	 cgs_end = cgs.end(); !marked_empty() && i != cgs_end; ++i)
    refine_no_check(*i);
}

template <typename T>
inline void
BD_Shape<T>::refine_no_check(const Congruence& cg) {
  assert(!marked_empty());
  assert(cg.space_dimension() <= space_dimension());

  if (cg.is_proper_congruence()) {
    if (cg.is_inconsistent())
      set_empty();
    // Other proper congruences are just ignored.
    return;
  }

  assert(cg.is_equality());
  Constraint c(cg);
  refine_no_check(c);
}

template <typename T>
inline bool
BD_Shape<T>::can_recycle_constraint_systems() {
  return false;
}


template <typename T>
inline bool
BD_Shape<T>::can_recycle_congruence_systems() {
  return false;
}

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.
    set_shortest_path_closed();
  add_constraints(cs);
}

template <typename T>
template <typename Interval>
inline
BD_Shape<T>::BD_Shape(const Box<Interval>& box,
                      Complexity_Class)
  : dbm(box.space_dimension() + 1), status(), redundancy_dbm() {
  // Check for emptyness for maximum precision.
  if (box.is_empty())
    set_empty();
  else if (box.space_dimension() > 0) {
    // A (non zero-dim) universe BDS is shortest-path closed.
    set_shortest_path_closed();
    refine_with_constraints(box.constraints());
  }
}

template <typename T>
inline
BD_Shape<T>::BD_Shape(const Grid& grid,
                      Complexity_Class)
  : dbm(grid.space_dimension() + 1), status(), redundancy_dbm() {
  if (grid.space_dimension() > 0)
    // A (non zero-dim) universe BDS is shortest-path closed.
    set_shortest_path_closed();
  // Taking minimized congruences ensures maximum precision.
  refine_with_congruences(grid.minimized_congruences());
}

template <typename T>
template <typename U>
inline
BD_Shape<T>::BD_Shape(const Octagonal_Shape<U>& os,
                      Complexity_Class)
  : dbm(os.space_dimension() + 1), status(), redundancy_dbm() {
  // Check for emptyness for maximum precision.
  if (os.is_empty())
    set_empty();
  else if (os.space_dimension() > 0) {
    // A (non zero-dim) universe BDS is shortest-path closed.
    set_shortest_path_closed();
    refine_with_constraints(os.constraints());
    // After refining, shortest-path closure is possibly lost
    // (even when `os' was strongly closed: recall that U
    // is possibly different from T).
  }
}

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
BD_Shape<T>::bounds_from_above(const Linear_Expression& expr) const {
  return bounds(expr, true);
}

template <typename T>
inline bool
BD_Shape<T>::bounds_from_below(const Linear_Expression& expr) const {
  return bounds(expr, false);
}

template <typename T>
inline bool
BD_Shape<T>::maximize(const Linear_Expression& expr,
		      Coefficient& sup_n, Coefficient& sup_d,
		      bool& maximum) const {
  return max_min(expr, true, sup_n, sup_d, maximum);
}

template <typename T>
inline bool
BD_Shape<T>::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);
}

template <typename T>
inline bool
BD_Shape<T>::minimize(const Linear_Expression& expr,
		      Coefficient& inf_n, Coefficient& inf_d,
		      bool& minimum) const {
  return max_min(expr, false, inf_n, inf_d, minimum);
}

template <typename T>
inline bool
BD_Shape<T>::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);
}

template <typename T>
inline bool
BD_Shape<T>::is_topologically_closed() const {
  return true;
}

template <typename T>
inline bool
BD_Shape<T>::is_discrete() const {
  return affine_dimension() == 0;
}

template <typename T>
inline void
BD_Shape<T>::topological_closure_assign() {
  // Nothing to be done.
  return;
}

/*! \relates BD_Shape */
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;
}

/*! \relates BD_Shape */
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
      assign_r(r, PLUS_INFINITY, ROUND_NOT_NEEDED);
    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
      assign_r(r, PLUS_INFINITY, ROUND_NOT_NEEDED);
   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) {
  typedef Checked_Number<Temp, Extended_Number_Policy> Checked_Temp;
  PPL_DIRTY_TEMP(Checked_Temp, tmp0);
  PPL_DIRTY_TEMP(Checked_Temp, tmp1);
  PPL_DIRTY_TEMP(Checked_Temp, 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
      assign_r(r, PLUS_INFINITY, ROUND_NOT_NEEDED);
    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
      assign_r(r, PLUS_INFINITY, ROUND_NOT_NEEDED);
   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) {
  typedef Checked_Number<Temp, Extended_Number_Policy> Checked_Temp;
  PPL_DIRTY_TEMP(Checked_Temp, tmp0);
  PPL_DIRTY_TEMP(Checked_Temp, tmp1);
  PPL_DIRTY_TEMP(Checked_Temp, 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
      assign_r(r, PLUS_INFINITY, ROUND_NOT_NEEDED);
    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
      assign_r(r, PLUS_INFINITY, ROUND_NOT_NEEDED);
   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) {
  typedef Checked_Number<Temp, Extended_Number_Policy> Checked_Temp;
  PPL_DIRTY_TEMP(Checked_Temp, tmp0);
  PPL_DIRTY_TEMP(Checked_Temp, tmp1);
  PPL_DIRTY_TEMP(Checked_Temp, 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,
				const 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())
      reset_shortest_path_closed();
  }
}

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);
  PPL_DIRTY_TEMP(N, k);
  div_round_up(k, num, den);
  add_dbm_constraint(i, j, k);
}

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 polyhedra documentation.
  C_Polyhedron px(constraints());
  C_Polyhedron py(y.constraints());
  px.time_elapse_assign(py);
  BD_Shape<T> x(px);
  swap(x);
  assert(OK());
}

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>::upper_bound_assign_and_minimize(const BD_Shape& y) {
  upper_bound_assign(y);
  assert(marked_empty()
	 || space_dimension() == 0 || marked_shortest_path_closed());
  return !marked_empty();
}

template <typename T>
inline bool
BD_Shape<T>::upper_bound_assign_if_exact(const BD_Shape& y) {
  // Dimension-compatibility check.
  if (space_dimension() != y.space_dimension())
    throw_dimension_incompatible("upper_bound_assign_if_exact(y)", y);
#if 0
  return BFT00_upper_bound_assign_if_exact(y);
#else
  return BHZ09_upper_bound_assign_if_exact(y);
#endif
}

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())
    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>::widening_assign(const BD_Shape& y, unsigned* tp) {
  H79_widening_assign(y, tp);
}

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 memory_size_type
BD_Shape<T>::total_memory_in_bytes() const {
  return sizeof(*this) + external_memory_in_bytes();
}

template <typename T>
inline int32_t
BD_Shape<T>::hash_code() const {
  return space_dimension() & 0x7fffffff;
}

} // 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 36. */
#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 Congruence_System& cgs)
  : dbm(cgs.space_dimension() + 1),
    status(),
    redundancy_dbm() {
  add_congruences(cgs);
}

template <typename T>
BD_Shape<T>::BD_Shape(const Generator_System& gs)
  : dbm(gs.space_dimension() + 1), status(), redundancy_dbm() {
  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();
    return;
  }

  const dimension_type space_dim = space_dimension();
  DB_Row<N>& dbm_0 = dbm[0];
  PPL_DIRTY_TEMP(N, tmp);

  bool dbm_initialized = false;
  bool point_seen = false;
  // Going through all the points and closure points.
  for (Generator_System::const_iterator gs_i = gs_begin;
       gs_i != gs_end; ++gs_i) {
    const Generator& g = *gs_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_generic("BD_Shape(gs)",
                  "the non-empty generator system gs contains no points.");

  // Going through all the lines and rays.
  for (Generator_System::const_iterator gs_i = gs_begin;
       gs_i != gs_end; ++gs_i) {
    const Generator& g = *gs_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)))
            assign_r(dbm_i[j], PLUS_INFINITY, ROUND_NOT_NEEDED);
        if (g_i != 0)
          assign_r(dbm_i[0], PLUS_INFINITY, ROUND_NOT_NEEDED);
      }
      for (dimension_type j = space_dim; j > 0; --j)
        if (g.coefficient(Variable(j-1)) != 0)
          assign_r(dbm_0[j], PLUS_INFINITY, ROUND_NOT_NEEDED);
      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)))
            assign_r(dbm_i[j], PLUS_INFINITY, ROUND_NOT_NEEDED);
        if (g_i < 0)
          assign_r(dbm_i[0], PLUS_INFINITY, ROUND_NOT_NEEDED);
      }
      for (dimension_type j = space_dim; j > 0; --j)
        if (g.coefficient(Variable(j-1)) > 0)
          assign_r(dbm_0[j], PLUS_INFINITY, ROUND_NOT_NEEDED);
      break;
    default:
      // Points and closure points already dealt with.
      break;
    }
  }
  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() {
  const dimension_type num_dimensions = ph.space_dimension();

  if (ph.marked_empty()) {
    *this = BD_Shape<T>(num_dimensions, EMPTY);
    return;
  }

  if (num_dimensions == 0) {
    *this = BD_Shape<T>(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<T>(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<T>(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<T>(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) {
    MIP_Problem lp(num_dimensions);
    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(),
             ph_cs_end = ph_cs.end(); i != ph_cs_end; ++i) {
        const Constraint& c = *i;
        if (c.is_strict_inequality())
          lp.add_constraint(Linear_Expression(c) >= 0);
        else
          lp.add_constraint(c);
      }

    // Check for unsatisfiability.
    if (!lp.is_satisfiable()) {
      *this = BD_Shape<T>(num_dimensions, EMPTY);
      return;
    }

    // Start with a universe BDS that will be refined by the simplex.
    *this = BD_Shape<T>(num_dimensions, UNIVERSE);
    // Get all the upper bounds.
    Generator g(point());
    PPL_DIRTY_TEMP_COEFFICIENT(num);
    PPL_DIRTY_TEMP_COEFFICIENT(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);
      if (lp.solve() == OPTIMIZED_MIP_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);
        if (lp.solve() == OPTIMIZED_MIP_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);
      if (lp.solve() == OPTIMIZED_MIP_PROBLEM) {
        g = lp.optimizing_point();
        lp.evaluate_objective_function(g, num, den);
        div_round_up(dbm[i][0], num, den);
      }
    }
    set_shortest_path_closed();
    assert(OK());
    return;
  }

  // Extract easy-to-find bounds from constraints.
  assert(complexity == POLYNOMIAL_COMPLEXITY);
  *this = BD_Shape<T>(num_dimensions, UNIVERSE);
  refine_with_constraints(ph.constraints());
}

template <typename T>
dimension_type
BD_Shape<T>::affine_dimension() const {
  const dimension_type space_dim = space_dimension();
  // A zero-space-dim shape always has affine dimension zero.
  if (space_dim == 0)
    return 0;

  // 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>
Congruence_System
BD_Shape<T>::minimized_congruences() const {
  // Shortest-path closure is necessary to detect emptiness
  // and all (possibly implicit) equalities.
  shortest_path_closure_assign();

  const dimension_type space_dim = space_dimension();
  Congruence_System cgs;
  if (space_dim == 0) {
    if (marked_empty())
      cgs = Congruence_System::zero_dim_empty();
  }
  else if (marked_empty())
    cgs.insert((0*Variable(space_dim-1) %= 1) / 0);
  else {
    // KLUDGE: in the future `cgs' will be constructed of the right dimension.
    // For the time being, we force the dimension with the following line.
    cgs.insert(0*Variable(space_dim-1) == 0);

    PPL_DIRTY_TEMP_COEFFICIENT(num);
    PPL_DIRTY_TEMP_COEFFICIENT(den);

    // Compute leader information.
    std::vector<dimension_type> leaders;
    compute_leaders(leaders);

    // 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);
          cgs.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);
          cgs.insert(den*Variable(leader-1) - den*Variable(i-1) == num);
        }
      }
    }
  }
  return cgs;
}

template <typename T>
void
BD_Shape<T>::add_constraint(const Constraint& c) {
  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);

  // Get rid of strict inequalities.
  if (c.is_strict_inequality()) {
    if (c.is_inconsistent()) {
      set_empty();
      return;
    }
    if (c.is_tautological())
      return;
    // Nontrivial strict inequalities are not allowed.
    throw_generic("add_constraint(c)", "strict inequalities are not allowed");
  }

  dimension_type num_vars = 0;
  dimension_type i = 0;
  dimension_type j = 0;
  PPL_DIRTY_TEMP_COEFFICIENT(coeff);
  // Constraints that are not bounded differences are not allowed.
  if (!extract_bounded_difference(c, c_space_dim, num_vars, i, j, coeff))
    throw_generic("add_constraint(c)",
                  "c is not a bounded difference constraint");

  const Coefficient& inhomo = c.inhomogeneous_term();
  if (num_vars == 0) {
    // Dealing with a trivial constraint (not a strict inequality).
    if (inhomo < 0
        || (inhomo != 0 && c.is_equality()))
      set_empty();
    return;
  }

  // Select the cell to be modified for the "<=" part of the constraint,
  // and set `coeff' to the absolute value of itself.
  const bool negative = (coeff < 0);
  N& x = negative ? dbm[i][j] : dbm[j][i];
  N& y = negative ? dbm[j][i] : dbm[i][j];
  if (negative)
    neg_assign(coeff);

  bool changed = false;
  // Compute the bound for `x', rounding towards plus infinity.
  PPL_DIRTY_TEMP(N, d);
  div_round_up(d, inhomo, coeff);
  if (x > d) {
    x = d;
    changed = true;
  }

  if (c.is_equality()) {
    // Also compute the bound for `y', rounding towards plus infinity.
    PPL_DIRTY_TEMP_COEFFICIENT(minus_c_term);
    neg_assign(minus_c_term, inhomo);
    div_round_up(d, minus_c_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 bounded difference shape.
  if (changed && marked_shortest_path_closed())
    reset_shortest_path_closed();
  assert(OK());
}

template <typename T>
void
BD_Shape<T>::add_congruence(const Congruence& cg) {
  const dimension_type cg_space_dim = cg.space_dimension();
  // Dimension-compatibility check:
  // the dimension of `cg' can not be greater than space_dim.
  if (space_dimension() < cg_space_dim)
    throw_dimension_incompatible("add_congruence(cg)", cg);

  // Handle the case of proper congruences first.
  if (cg.is_proper_congruence()) {
    if (cg.is_tautological())
      return;
    if (cg.is_inconsistent()) {
      set_empty();
      return;
    }
    // Non-trivial and proper congruences are not allowed.
    throw_generic("add_congruence(cg)",
                  "cg is a non-trivial, proper congruence");
  }

  assert(cg.is_equality());
  Constraint c(cg);
  add_constraint(c);
}

template <typename T>
void
BD_Shape<T>::refine_no_check(const Constraint& c) {
  assert(!marked_empty());
  const dimension_type c_space_dim = c.space_dimension();
  assert(c_space_dim <= space_dimension());

  dimension_type num_vars = 0;
  dimension_type i = 0;
  dimension_type j = 0;
  PPL_DIRTY_TEMP_COEFFICIENT(coeff);
  // Constraints that are not bounded differences are ignored.
  if (!extract_bounded_difference(c, c_space_dim, num_vars, i, j, coeff))
    return;

  const Coefficient& inhomo = c.inhomogeneous_term();
  if (num_vars == 0) {
    // Dealing with a trivial constraint (might be a strict inequality).
    if (inhomo < 0
        || (c.is_equality() && inhomo != 0)
        || (c.is_strict_inequality() && inhomo == 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.
  const bool negative = (coeff < 0);
  N& x = negative ? dbm[i][j] : dbm[j][i];
  N& y = negative ? dbm[j][i] : dbm[i][j];
  if (negative)
    neg_assign(coeff);

  bool changed = false;
  // Compute the bound for `x', rounding towards plus infinity.
  PPL_DIRTY_TEMP(N, d);
  div_round_up(d, inhomo, coeff);
  if (x > d) {
    x = d;
    changed = true;
  }

  if (c.is_equality()) {
    // Also compute the bound for `y', rounding towards plus infinity.
    PPL_DIRTY_TEMP_COEFFICIENT(minus_c_term);
    neg_assign(minus_c_term, inhomo);
    div_round_up(d, minus_c_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 bounded difference shape.
  if (changed && marked_shortest_path_closed())
    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 bounded difference shape,
  // let `*this' become empty.
  if (y_space_dim == 0 && y.marked_empty()) {
    set_empty();
    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())
    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' bounded difference shape 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_disjoint_from(const BD_Shape& y) const {
  const dimension_type space_dim = space_dimension();
  // Dimension-compatibility check.
  if (space_dim != y.space_dimension())
    throw_dimension_incompatible("is_disjoint_from(y)", y);

  // If one of the two bounded difference shape is empty,
  // then the two bounded difference shape are disjoint.
  shortest_path_closure_assign();
  if (marked_empty())
    return true;
  y.shortest_path_closure_assign();
  if (y.marked_empty())
    return true;

  // Two BDSs are disjoint when their intersection is empty.
  // That is if and only if there exists at least a bounded difference
  // such that the upper bound of the bounded difference in the first
  // BD_Shape is strictly less than the lower bound of
  // the corresponding bounded difference in the second BD_Shape
  // or vice versa.
  // For example: let be
  // in `*this':    -a_j_i <= v_j - v_i <= a_i_j;
  // and in `y':    -b_j_i <= v_j - v_i <= b_i_j;
  // `*this' and `y' are disjoint if
  // 1.) a_i_j < -b_j_i or
  // 2.) b_i_j < -a_j_i.
  PPL_DIRTY_TEMP(N, tmp);
  for (dimension_type i = space_dim+1; i-- > 0; ) {
    const DB_Row<N>& x_i = dbm[i];
    for (dimension_type j = space_dim+1; j-- > 0; ) {
      neg_assign_r(tmp, y.dbm[j][i], ROUND_UP);
      if (x_i[j] < tmp)
        return true;
    }
  }

  return false;
}

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 bounded difference shape 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>
bool
BD_Shape<T>::is_bounded() const {
  shortest_path_closure_assign();
  const dimension_type space_dim = space_dimension();
  // A zero-dimensional or empty BDS is bounded.
  if (marked_empty() || space_dim == 0)
    return true;

  // A bounded difference shape defining the bounded BDS never can
  // 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 (i != j)
        if (is_plus_infinity(dbm_i[j]))
          return false;
  }

  return true;
}

template <typename T>
bool
BD_Shape<T>::contains_integer_point() const {
  // Force shortest-path closure.
  if (is_empty())
    return false;

  const dimension_type space_dim = space_dimension();
  if (space_dim == 0)
    return true;

  // A non-empty BD_Shape defined by integer constraints
  // necessarily contains an integer point.
  if (std::numeric_limits<T>::is_integer)
    return true;

  // Build an integer BD_Shape z with bounds at least as tight as
  // those in *this and then recheck for emptiness.
  BD_Shape<mpz_class> bds_z(space_dim);
  typedef BD_Shape<mpz_class>::N Z;
  bds_z.reset_shortest_path_closed();
  PPL_DIRTY_TEMP(N, tmp);
  bool all_integers = true;
  for (dimension_type i = space_dim + 1; i-- > 0; ) {
    DB_Row<Z>& z_i = bds_z.dbm[i];
    const DB_Row<N>& dbm_i = dbm[i];
    for (dimension_type j = space_dim + 1; j-- > 0; ) {
      const N& dbm_i_j = dbm_i[j];
      if (is_plus_infinity(dbm_i_j))
        continue;
      if (is_integer(dbm_i_j))
        assign_r(z_i[j], dbm_i_j, ROUND_NOT_NEEDED);
      else {
        all_integers = false;
        Z& z_i_j = z_i[j];
        // Copy dbm_i_j into z_i_j, but rounding downwards.
        neg_assign_r(tmp, dbm_i_j, ROUND_NOT_NEEDED);
        assign_r(z_i_j, tmp, ROUND_UP);
        neg_assign_r(z_i_j, z_i_j, ROUND_NOT_NEEDED);
      }
    }
  }
  return all_integers || !bds_z.is_empty();
}

template <typename T>
bool
BD_Shape<T>::constrains(const Variable var) const {
  // `var' should be one of the dimensions of the polyhedron.
  const dimension_type var_space_dim = var.space_dimension();
  if (space_dimension() < var_space_dim)
    throw_dimension_incompatible("constrains(v)", "v", var);

  // A polyhedron known to be empty constrains all variables.
  // (Note: do not force emptiness check _yet_)
  if (marked_empty())
    return true;

  // Check whether `var' is syntactically constrained.
  const DB_Row<N>& dbm_v = dbm[var_space_dim];
  for (dimension_type i = dbm.num_rows(); i-- > 0; ) {
    if (!is_plus_infinity(dbm_v[i])
        || !is_plus_infinity(dbm[i][var_space_dim]))
      return true;
  }

  // `var' is not syntactically constrained:
  // now force an emptiness check.
  return is_empty();
}

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]
            && is_additive_inverse(dbm[j][i], 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, l_size = leaders.size(); i != l_size; ++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;

  const dimension_type space_dim = space_dimension();
  // Zero-dimensional BDSs are necessarily reduced.
  if (space_dim == 0)
    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;
  x_copy.shortest_path_closure_assign();
  // If we just discovered emptiness, 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(space_dim + 1);

  // We store the leader.
  for (dimension_type i = 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 < space_dim; ++i) {
    const DB_Row<N>& x_copy_dbm_i = x_copy.dbm[i];
    for (dimension_type j = i + 1; j <= space_dim; ++j)
      if (is_additive_inverse(x_copy.dbm[j][i], x_copy_dbm_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 bounded difference shape, 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.
  PPL_DIRTY_TEMP(N, c);
  for (dimension_type k = 0; k <= space_dim; ++k)
    if (leader[k] == k) {
      const DB_Row<N>& x_k = x_copy.dbm[k];
      for (dimension_type i = 0; i <= space_dim; ++i)
        if (leader[i] == i) {
          const DB_Row<N>& x_i = x_copy.dbm[i];
          const Bit_Row& redundancy_i = redundancy_dbm[i];
          const N& x_i_k = x_i[k];
          for (dimension_type j = 0; j <= 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(space_dim + 1);
  for (dimension_type i = space_dim + 1; i-- > 0; )
    var_conn[i] = 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 <= 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 <= 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 <= 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(space_dim + 1);
  for (dimension_type i = 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 <= 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 != 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>
bool
BD_Shape<T>::bounds(const Linear_Expression& expr,
                    const bool from_above) const {
  // The dimension of `expr' should not be greater than the dimension
  // of `*this'.
  const dimension_type expr_space_dim = expr.space_dimension();
  const dimension_type space_dim = space_dimension();
  if (space_dim < expr_space_dim)
    throw_dimension_incompatible((from_above
                                  ? "bounds_from_above(e)"
                                  : "bounds_from_below(e)"), "e", expr);

  shortest_path_closure_assign();
  // A zero-dimensional or empty BDS bounds everything.
  if (space_dim == 0 || marked_empty())
    return true;

  // The constraint `c' is used to check if `expr' is a difference
  // bounded and, in this case, to select the cell.
  const Constraint& c = from_above ? expr <= 0 : expr >= 0;
  const dimension_type c_space_dim = c.space_dimension();
  dimension_type num_vars = 0;
  dimension_type i = 0;
  dimension_type j = 0;
  PPL_DIRTY_TEMP_COEFFICIENT(coeff);
  // Check if `c' is a BD constraint.
  if (extract_bounded_difference(c, c_space_dim, num_vars, i, j, coeff)) {
    if (num_vars == 0)
      // Dealing with a trivial constraint.
      return true;
    // Select the cell to be checked.
    const N& x = (coeff < 0) ? dbm[i][j] : dbm[j][i];
    return !is_plus_infinity(x);
  }
  else {
    // Not a DB constraint: use the MIP solver.
    Optimization_Mode mode_bounds
      = from_above ? MAXIMIZATION : MINIMIZATION;
    MIP_Problem mip(space_dim, constraints(), expr, mode_bounds);
    // Problem is known to be feasible.
    return (mip.solve() == OPTIMIZED_MIP_PROBLEM);
  }
}

template <typename T>
bool
BD_Shape<T>::max_min(const Linear_Expression& expr,
                     const bool maximize,
                     Coefficient& ext_n, Coefficient& ext_d,
                     bool& included) const {
  // 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((maximize
                                  ? "maximize(e, ...)"
                                  : "minimize(e, ...)"), "e", expr);
  // Deal with zero-dim BDS first.
  if (space_dim == 0) {
    if (marked_empty())
      return false;
    else {
      ext_n = expr.inhomogeneous_term();
      ext_d = 1;
      included = true;
      return true;
    }
  }

  shortest_path_closure_assign();
  // For an empty BDS we simply return false.
  if (marked_empty())
    return false;

  // The constraint `c' is used to check if `expr' is a difference
  // bounded and, in this case, to select the cell.
  const Constraint& c = maximize ? expr <= 0 : expr >= 0;
  const dimension_type c_space_dim = c.space_dimension();
  dimension_type num_vars = 0;
  dimension_type i = 0;
  dimension_type j = 0;
  PPL_DIRTY_TEMP_COEFFICIENT(coeff);
  // Check if `c' is a BD constraint.
  if (!extract_bounded_difference(c, c_space_dim, num_vars, i, j, coeff)) {
    Optimization_Mode mode_max_min
      = maximize ? MAXIMIZATION : MINIMIZATION;
    MIP_Problem mip(space_dim, constraints(), expr, mode_max_min);
    if (mip.solve() == OPTIMIZED_MIP_PROBLEM) {
      mip.optimal_value(ext_n, ext_d);
      included = true;
      return true;
    }
    else
      // Here`expr' is unbounded in `*this'.
      return false;
  }
  else {
    // Here `expr' is a bounded difference.
    if (num_vars == 0) {
      // Dealing with a trivial expression.
      ext_n = expr.inhomogeneous_term();
      ext_d = 1;
      included = true;
      return true;
    }

    // Select the cell to be checked.
    const N& x = (coeff < 0) ? dbm[i][j] : dbm[j][i];
    if (!is_plus_infinity(x)) {
      // Compute the maximize/minimize of `expr'.
      PPL_DIRTY_TEMP(N, d);
      const Coefficient& b = expr.inhomogeneous_term();
      PPL_DIRTY_TEMP_COEFFICIENT(minus_b);
      neg_assign(minus_b, b);
      const Coefficient& sc_b = maximize ? b : minus_b;
      assign_r(d, sc_b, ROUND_UP);
      // Set `coeff_expr' to the absolute value of coefficient of
      // a variable in `expr'.
      PPL_DIRTY_TEMP(N, coeff_expr);
      const Coefficient& coeff_i = expr.coefficient(Variable(i-1));
      const int sign_i = sgn(coeff_i);
      if (sign_i > 0)
        assign_r(coeff_expr, coeff_i, ROUND_UP);
      else {
        PPL_DIRTY_TEMP_COEFFICIENT(minus_coeff_i);
        neg_assign(minus_coeff_i, coeff_i);
        assign_r(coeff_expr, minus_coeff_i, ROUND_UP);
      }
      // Approximating the maximum/minimum of `expr'.
      add_mul_assign_r(d, coeff_expr, x, ROUND_UP);
      numer_denom(d, ext_n, ext_d);
      if (!maximize)
        neg_assign(ext_n);
      included = true;
      return true;
    }

    // `expr' is unbounded.
    return false;
  }
}

template <typename T>
bool
BD_Shape<T>::max_min(const Linear_Expression& expr,
                     const bool maximize,
                     Coefficient& ext_n, Coefficient& ext_d,
                     bool& included,
                     Generator& g) const {
  // 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((maximize
                                  ? "maximize(e, ...)"
                                  : "minimize(e, ...)"), "e", expr);
  // Deal with zero-dim BDS first.
  if (space_dim == 0) {
    if (marked_empty())
      return false;
    else {
      ext_n = expr.inhomogeneous_term();
      ext_d = 1;
      included = true;
      g = point();
      return true;
    }
  }

  shortest_path_closure_assign();
  // For an empty BDS we simply return false.
  if (marked_empty())
    return false;

  Optimization_Mode mode_max_min
    = maximize ? MAXIMIZATION : MINIMIZATION;
  MIP_Problem mip(space_dim, constraints(), expr, mode_max_min);
  if (mip.solve() == OPTIMIZED_MIP_PROBLEM) {
    g = mip.optimizing_point();
    mip.evaluate_objective_function(g, ext_n, ext_d);
    included = true;
    return true;
  }
  // Here `expr' is unbounded in `*this'.
  return false;
}

template <typename T>
Poly_Con_Relation
BD_Shape<T>::relation_with(const Congruence& cg) const {
  const dimension_type cg_space_dim = cg.space_dimension();
  const dimension_type space_dim = space_dimension();

  // Dimension-compatibility check.
  if (cg_space_dim > space_dim)
    throw_dimension_incompatible("relation_with(cg)", cg);

  // If the congruence is a bounded difference equality,
  // find the relation with the equivalent equality constraint.
  if (cg.is_equality()) {
    Constraint c(cg);
    dimension_type num_vars = 0;
    dimension_type i = 0;
    dimension_type j = 0;
    PPL_DIRTY_TEMP_COEFFICIENT(coeff);
    if (extract_bounded_difference(c, cg_space_dim, num_vars,
                                    i, j, coeff))
      return relation_with(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 (cg.is_inconsistent())
      return Poly_Con_Relation::is_disjoint();
    else if (cg.inhomogeneous_term() % cg.modulus() == 0)
      return Poly_Con_Relation::saturates()
        && Poly_Con_Relation::is_included();
  }

  PPL_DIRTY_TEMP(Coefficient, min_num);
  PPL_DIRTY_TEMP(Coefficient, min_den);
  bool min_included;
  PPL_DIRTY_TEMP_COEFFICIENT(mod);
  mod = cg.modulus();
  Linear_Expression le;
  for (dimension_type i = cg_space_dim; i-- > 0; )
    le += cg.coefficient(Variable(i)) * Variable(i);
  bool bounded_below = minimize(le, min_num, min_den, min_included);

  if (!bounded_below)
    return Poly_Con_Relation::strictly_intersects();

  PPL_DIRTY_TEMP_COEFFICIENT(v);
  PPL_DIRTY_TEMP_COEFFICIENT(lower_num);
  PPL_DIRTY_TEMP_COEFFICIENT(lower_den);
  PPL_DIRTY_TEMP_COEFFICIENT(lower);
  assign_r(lower_num, min_num, ROUND_NOT_NEEDED);
  assign_r(lower_den, min_den, ROUND_NOT_NEEDED);
  neg_assign(v, cg.inhomogeneous_term());
  lower = lower_num / lower_den;
  v += ((lower / mod) * mod);
  if (v * lower_den < lower_num)
    v += mod;
  const Constraint& c(le == v);
  return relation_with(c);
}


template <typename T>
Poly_Con_Relation
BD_Shape<T>::relation_with(const Constraint& c) const {
  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;
  PPL_DIRTY_TEMP_COEFFICIENT(coeff);
  if (!extract_bounded_difference(c, c_space_dim, num_vars, i, j, coeff)) {
    // Constraints that are not bounded differences.
    // Use maximize() and minimize() to do much of the work.

    // Find the linear expression for the constraint and use that to
    // find if the expression is bounded from above or below and if it
    // is, find the maximum and minimum values.
    Linear_Expression le;
    for (dimension_type k = c_space_dim; k-- > 0; ) {
      Variable vk(k);
      le += c.coefficient(vk) * vk;
    }
    PPL_DIRTY_TEMP(Coefficient, max_num);
    PPL_DIRTY_TEMP(Coefficient, max_den);
    bool max_included;
    PPL_DIRTY_TEMP(Coefficient, min_num);
    PPL_DIRTY_TEMP(Coefficient, min_den);
    bool min_included;
    bool bounded_above = maximize(le, max_num, max_den, max_included);
    bool bounded_below = minimize(le, min_num, min_den, min_included);
    if (!bounded_above) {
      if (!bounded_below)
        return Poly_Con_Relation::strictly_intersects();
      min_num += c.inhomogeneous_term() * min_den;
      switch (sgn(min_num)) {
      case 1:
        if (c.is_equality())
          return  Poly_Con_Relation::is_disjoint();
        return  Poly_Con_Relation::is_included();
      case 0:
        if (c.is_strict_inequality() || c.is_equality())
          return  Poly_Con_Relation::strictly_intersects();
        return  Poly_Con_Relation::is_included();
      case -1:
        return  Poly_Con_Relation::strictly_intersects();
      }
    }
    if (!bounded_below) {
      max_num += c.inhomogeneous_term() * max_den;
      switch (sgn(max_num)) {
      case 1:
        return  Poly_Con_Relation::strictly_intersects();
      case 0:
        if (c.is_strict_inequality())
          return  Poly_Con_Relation::is_disjoint();
        return  Poly_Con_Relation::strictly_intersects();
      case -1:
        return  Poly_Con_Relation::is_disjoint();
      }
    }
    else {
      max_num += c.inhomogeneous_term() * max_den;
      min_num += c.inhomogeneous_term() * min_den;
      switch (sgn(max_num)) {
      case 1:
        switch (sgn(min_num)) {
        case 1:
          if (c.is_equality())
            return  Poly_Con_Relation::is_disjoint();
          return  Poly_Con_Relation::is_included();
        case 0:
          if (c.is_equality())
            return  Poly_Con_Relation::strictly_intersects();
          if (c.is_strict_inequality())
            return  Poly_Con_Relation::strictly_intersects();
          return  Poly_Con_Relation::is_included();
        case -1:
          return  Poly_Con_Relation::strictly_intersects();
        }
     case 0:
        if (min_num == 0) {
          if (c.is_strict_inequality())
            return  Poly_Con_Relation::is_disjoint()
              && Poly_Con_Relation::saturates();
          return  Poly_Con_Relation::is_included()
            && Poly_Con_Relation::saturates();
        }
        if (c.is_strict_inequality())
          return  Poly_Con_Relation::is_disjoint();
        return  Poly_Con_Relation::strictly_intersects();
      case -1:
        return  Poly_Con_Relation::is_disjoint();
      }
    }
  }

  // Constraints that are bounded differences.
  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:
      if (c.is_equality())
        return Poly_Con_Relation::is_disjoint();
      else
        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 bool negative = (coeff < 0);
  const N& x = negative ? dbm[i][j] : dbm[j][i];
  const N& y = negative ? dbm[j][i] : dbm[i][j];
  if (negative)
    neg_assign(coeff);
  // Deduce the relation/s of the constraint `c' of the form
  // `coeff*v - coeff*u </<=/== c.inhomogeneous_term()'
  // with the respectively constraints in `*this'
  // `-y <= v - u <= x'.
  // Let `d == c.inhomogeneous_term()/coeff'
  // and `d1 == -c.inhomogeneous_term()/coeff'.
  // The following variables of mpq_class type are used to be precise
  // when the bds is defined by integer constraints.
  PPL_DIRTY_TEMP0(mpq_class, q_x);
  PPL_DIRTY_TEMP0(mpq_class, q_y);
  PPL_DIRTY_TEMP0(mpq_class, d);
  PPL_DIRTY_TEMP0(mpq_class, d1);
  PPL_DIRTY_TEMP0(mpq_class, c_den);
  PPL_DIRTY_TEMP0(mpq_class, q_den);
  assign_r(c_den, coeff, ROUND_NOT_NEEDED);
  assign_r(d, c.inhomogeneous_term(), ROUND_NOT_NEEDED);
  neg_assign_r(d1, d, ROUND_NOT_NEEDED);
  div_assign_r(d, d, c_den, ROUND_NOT_NEEDED);
  div_assign_r(d1, d1, c_den, ROUND_NOT_NEEDED);

  if (is_plus_infinity(x)) {
    if (!is_plus_infinity(y)) {
      // `*this' is in the following form:
      // `-y <= v - u'.
      // In this case `*this' is disjoint from `c' if
      // `-y > d' (`-y >= d' if c is a strict equality), i.e. if
      // `y < d1' (`y <= d1' if c is a strict equality).
      PPL_DIRTY_TEMP_COEFFICIENT(numer);
      PPL_DIRTY_TEMP_COEFFICIENT(denom);
      numer_denom(y, numer, denom);
      assign_r(q_den, denom, ROUND_NOT_NEEDED);
      assign_r(q_y, numer, ROUND_NOT_NEEDED);
      div_assign_r(q_y, q_y, q_den, ROUND_NOT_NEEDED);
      if (q_y < d1)
        return Poly_Con_Relation::is_disjoint();
      if (q_y == d1 && c.is_strict_inequality())
        return Poly_Con_Relation::is_disjoint();
    }

    // In all other cases `*this' intersects `c'.
    return Poly_Con_Relation::strictly_intersects();
  }

  // Here `x' is not plus-infinity.
  PPL_DIRTY_TEMP_COEFFICIENT(numer);
  PPL_DIRTY_TEMP_COEFFICIENT(denom);
  numer_denom(x, numer, denom);
  assign_r(q_den, denom, ROUND_NOT_NEEDED);
  assign_r(q_x, numer, ROUND_NOT_NEEDED);
  div_assign_r(q_x, q_x, q_den, ROUND_NOT_NEEDED);

  if (!is_plus_infinity(y)) {
    numer_denom(y, numer, denom);
    assign_r(q_den, denom, ROUND_NOT_NEEDED);
    assign_r(q_y, numer, ROUND_NOT_NEEDED);
    div_assign_r(q_y, q_y, q_den, ROUND_NOT_NEEDED);
    if (q_x == d && q_y == d1) {
      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();
    }
    // `*this' is disjoint from `c' when
    // `-y > d' (`-y >= d' if c is a strict equality), i.e. if
    // `y < d1' (`y <= d1' if c is a strict equality).
    if (q_y < d1)
      return Poly_Con_Relation::is_disjoint();
    if (q_y == d1 && c.is_strict_inequality())
      return Poly_Con_Relation::is_disjoint();
  }

  // Here `y' can be also plus-infinity.
  // If `c' is an equality, `*this' is disjoint from `c' if
  // `x < d'.
  if (d > q_x) {
    if (c.is_equality())
      return Poly_Con_Relation::is_disjoint();
    else
      return Poly_Con_Relation::is_included();
  }

  if (d == q_x && c.is_nonstrict_inequality())
    return Poly_Con_Relation::is_included();

  // In all other cases `*this' intersects `c'.
  return Poly_Con_Relation::strictly_intersects();
}

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);

  shortest_path_closure_assign();
  // The empty BDS cannot subsume a generator.
  if (marked_empty())
    return Poly_Gen_Relation::nothing();

  // A universe BDS 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();
  const bool is_line_or_ray = g.is_line_or_ray();

  // The relation between the BDS and the given generator is obtained
  // checking if the generator satisfies all the constraints in the BDS.
  // 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 BDS.

  // Allocation of temporaries done once and for all.
  PPL_DIRTY_TEMP_COEFFICIENT(num);
  PPL_DIRTY_TEMP_COEFFICIENT(den);
  PPL_DIRTY_TEMP_COEFFICIENT(product);
  // We find in `*this' all the constraints.
  for (dimension_type i = 0; i <= space_dim; ++i) {
    const Coefficient& g_coeff_y = (i > g_space_dim || i == 0)
      ? Coefficient_zero() : g.coefficient(Variable(i-1));
    const DB_Row<N>& dbm_i = dbm[i];
    for (dimension_type j = i + 1; j <= space_dim; ++j) {
      const Coefficient& g_coeff_x = (j > g_space_dim)
        ? Coefficient_zero() : g.coefficient(Variable(j-1));
      const N& dbm_ij = dbm_i[j];
      const N& dbm_ji = dbm[j][i];
      if (is_additive_inverse(dbm_ji, dbm_ij)) {
        // We have one equality constraint: den*x - den*y = num.
        // Compute the scalar product.
        numer_denom(dbm_ij, num, den);
        product = 0;
        add_mul_assign(product, den, g_coeff_y);
        add_mul_assign(product, -den, g_coeff_x);
        if (!is_line_or_ray)
          add_mul_assign(product, num, g.divisor());
        if (product != 0)
          return Poly_Gen_Relation::nothing();
      }
      else {
        // We have 0, 1 or 2 binary inequality constraint/s.
        if (!is_plus_infinity(dbm_ij)) {
          // We have the binary inequality constraint: den*x - den*y <= num.
          // Compute the scalar product.
          numer_denom(dbm_ij, num, den);
          product = 0;
          add_mul_assign(product, den, g_coeff_y);
          add_mul_assign(product, -den, g_coeff_x);
          if (!is_line_or_ray)
            add_mul_assign(product, num, g.divisor());
          if (is_line) {
            if (product != 0)
              // Lines must saturate all constraints.
              return Poly_Gen_Relation::nothing();
          }
          else
            // `g' is either a ray, a point or a closure point.
            if (product < 0)
              return Poly_Gen_Relation::nothing();
        }

        if (!is_plus_infinity(dbm_ji)) {
          // We have the binary inequality constraint: den*y - den*x <= b.
          // Compute the scalar product.
          numer_denom(dbm_ji, num, den);
          product = 0;
          add_mul_assign(product, den, g_coeff_x);
          add_mul_assign(product, -den, g_coeff_y);
          if (!is_line_or_ray)
            add_mul_assign(product, num, g.divisor());
          if (is_line) {
            if (product != 0)
              // Lines must saturate all constraints.
              return Poly_Gen_Relation::nothing();
          }
          else
            // `g' is either a ray, a point or a closure point.
            if (product < 0)
              return Poly_Gen_Relation::nothing();
        }
      }
    }
  }

  // The generator satisfies all the constraints.
  return Poly_Gen_Relation::subsumes();
}

template <typename T>
void
BD_Shape<T>::shortest_path_closure_assign() const {
  // 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);
  }

  PPL_DIRTY_TEMP(N, sum);
  for (dimension_type k = num_dimensions + 1; k-- > 0; ) {
    const DB_Row<N>& x_dbm_k = x.dbm[k];
    for (dimension_type i = num_dimensions + 1; i-- > 0; ) {
      DB_Row<N>& x_dbm_i = x.dbm[i];
      const N& x_dbm_i_k = x_dbm_i[k];
      if (!is_plus_infinity(x_dbm_i_k))
        for (dimension_type j = num_dimensions + 1; j-- > 0; ) {
          const N& x_dbm_k_j = x_dbm_k[j];
          if (!is_plus_infinity(x_dbm_k_j)) {
            // Rounding upward for correctness.
            add_assign_r(sum, x_dbm_i_k, x_dbm_k_j, ROUND_UP);
            min_assign(x_dbm_i[j], sum);
          }
        }
    }
  }

  // Check for emptiness: 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 (sgn(x_dbm_hh) < 0) {
      x.set_empty();
      return;
    }
    else {
      assert(sgn(x_dbm_hh) == 0);
      // Restore PLUS_INFINITY on the main diagonal.
      assign_r(x_dbm_hh, PLUS_INFINITY, ROUND_NOT_NEEDED);
    }
  }

  // The BDS is not empty and it is now shortest-path closed.
  x.set_shortest_path_closed();
}

template <typename T>
void
BD_Shape<T>::incremental_shortest_path_closure_assign(Variable var) const {
  // Do something only if necessary.
  if (marked_empty() || marked_shortest_path_closed())
    return;
  const dimension_type num_dimensions = space_dimension();
  assert(var.id() < num_dimensions);

  // Even though the BDS will not change, its internal representation
  // is going to be modified by the incremental Floyd-Warshall algorithm.
  BD_Shape& x = const_cast<BD_Shape&>(*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);
  }

  // Using the incremental Floyd-Warshall algorithm.
  PPL_DIRTY_TEMP(N, sum);
  const dimension_type v = var.id() + 1;
  DB_Row<N>& x_v = x.dbm[v];
  // Step 1: Improve all constraints on variable `var'.
  for (dimension_type k = num_dimensions + 1; k-- > 0; ) {
    DB_Row<N>& x_k = x.dbm[k];
    const N& x_v_k = x_v[k];
    const N& x_k_v = x_k[v];
    const bool x_v_k_finite = !is_plus_infinity(x_v_k);
    const bool x_k_v_finite = !is_plus_infinity(x_k_v);
    // Specialize inner loop based on finiteness info.
    if (x_v_k_finite) {
      if (x_k_v_finite) {
        // Here both x_v_k and x_k_v are finite.
        for (dimension_type i = num_dimensions + 1; i-- > 0; ) {
          DB_Row<N>& x_i = x.dbm[i];
          const N& x_i_k = x_i[k];
          if (!is_plus_infinity(x_i_k)) {
            add_assign_r(sum, x_i_k, x_k_v, ROUND_UP);
            min_assign(x_i[v], sum);
          }
          const N& x_k_i = x_k[i];
          if (!is_plus_infinity(x_k_i)) {
            add_assign_r(sum, x_v_k, x_k_i, ROUND_UP);
            min_assign(x_v[i], sum);
          }
        }
      }
      else {
        // Here x_v_k is finite, but x_k_v is not.
        for (dimension_type i = num_dimensions + 1; i-- > 0; ) {
          const N& x_k_i = x_k[i];
          if (!is_plus_infinity(x_k_i)) {
            add_assign_r(sum, x_v_k, x_k_i, ROUND_UP);
            min_assign(x_v[i], sum);
          }
        }
      }
    }
    else if (x_k_v_finite) {
      // Here x_v_k is infinite, but x_k_v is finite.
      for (dimension_type i = num_dimensions + 1; i-- > 0; ) {
        DB_Row<N>& x_i = x.dbm[i];
        const N& x_i_k = x_i[k];
        if (!is_plus_infinity(x_i_k)) {
          add_assign_r(sum, x_i_k, x_k_v, ROUND_UP);
          min_assign(x_i[v], sum);
        }
      }
    }
    else
      // Here both x_v_k and x_k_v are infinite.
      continue;
  }

  // Step 2: improve the other bounds by using the precise bounds
  // for the constraints on `var'.
  for (dimension_type i = num_dimensions + 1; i-- > 0; ) {
    DB_Row<N>& x_i = x.dbm[i];
    const N& x_i_v = x_i[v];
    if (!is_plus_infinity(x_i_v)) {
      for (dimension_type j = num_dimensions + 1; j-- > 0; ) {
        const N& x_v_j = x_v[j];
        if (!is_plus_infinity(x_v_j)) {
          add_assign_r(sum, x_i_v, x_v_j, ROUND_UP);
          min_assign(x_i[j], sum);
        }
      }
    }
  }

  // Check for emptiness: 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 (sgn(x_dbm_hh) < 0) {
      x.set_empty();
      return;
    }
    else {
      assert(sgn(x_dbm_hh) == 0);
      // Restore PLUS_INFINITY on the main diagonal.
      assign_r(x_dbm_hh, PLUS_INFINITY, ROUND_NOT_NEEDED);
    }
  }

  // The BDS is not empty and it is now shortest-path closed.
  x.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;

  const dimension_type space_dim = space_dimension();
  // Zero-dimensional BDSs are necessarily reduced.
  if (space_dim == 0)
    return;

  // First find the tightest 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();

  Bit_Matrix redundancy(space_dim + 1, space_dim + 1);
  // Init all constraints to be redundant.
  // TODO: provide an appropriate method to set multiple bits.
  Bit_Row& red_0 = redundancy[0];
  for (dimension_type j = space_dim + 1; j-- > 0; )
    red_0.set(j);
  for (dimension_type i = space_dim + 1; i-- > 0; )
    redundancy[i] = red_0;

  // Step 2: flag non-redundant constraints in the (zero-cycle-free)
  // subsystem of bounded differences having only leaders as variables.
  PPL_DIRTY_TEMP(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];
    Bit_Row& 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.clear(j);
        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.set(j);
            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].clear(j);
          // 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].clear(j);
        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.set_shortest_path_reduced();

  assert(is_shortest_path_reduced());
}

template <typename T>
void
BD_Shape<T>::upper_bound_assign(const BD_Shape& y) {
  const dimension_type space_dim = space_dimension();

  // Dimension-compatibility check.
  if (space_dim != y.space_dimension())
    throw_dimension_incompatible("upper_bound_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;
    }
  }
  // Shortest-path closure is maintained (if it was holding).
  // TODO: see whether reduction can be (efficiently!) maintained too.
  if (marked_shortest_path_reduced())
    reset_shortest_path_reduced();
  assert(OK());
}

template <typename T>
bool
BD_Shape<T>::BFT00_upper_bound_assign_if_exact(const BD_Shape& y) {
  // Declare a const reference to *this (to avoid accidental modifications).
  const BD_Shape& x = *this;
  const dimension_type x_space_dim = x.space_dimension();

  // Private method: the caller must ensure the following.
  assert(x_space_dim == y.space_dimension());

  // The zero-dim case is trivial.
  if (x_space_dim == 0) {
    upper_bound_assign(y);
    return true;
  }
  // If `x' or `y' is (known to be) empty, the upper bound is exact.
  if (x.marked_empty()) {
    *this = y;
    return true;
  }
  else if (y.is_empty())
    return true;
  else if (x.is_empty()) {
    *this = y;
    return true;
  }

  // Here both `x' and `y' are known to be non-empty.
  // Implementation based on Algorithm 4.1 (page 6) in [BemporadFT00TR],
  // tailored to the special case of BD shapes.

  Variable eps(x_space_dim);
  Linear_Expression zero_expr = 0*eps;
  Linear_Expression db_expr;
  PPL_DIRTY_TEMP_COEFFICIENT(num);
  PPL_DIRTY_TEMP_COEFFICIENT(den);

  // Step 1: compute the constraint system for the envelope env(x,y)
  // and put into x_cs_removed and y_cs_removed those non-redundant
  // constraints that are not in the constraint system for env(x,y).
  // While at it, also add the additional space dimension (eps).
  Constraint_System env_cs;
  Constraint_System x_cs_removed;
  Constraint_System y_cs_removed;
  x.shortest_path_reduction_assign();
  y.shortest_path_reduction_assign();
  for (dimension_type i = x_space_dim + 1; i-- > 0; ) {
    const Bit_Row& x_red_i = x.redundancy_dbm[i];
    const Bit_Row& y_red_i = y.redundancy_dbm[i];
    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_red_i[j] && y_red_i[j])
        continue;
      if (!x_red_i[j]) {
        const N& x_dbm_ij = x_dbm_i[j];
        assert(!is_plus_infinity(x_dbm_ij));
        numer_denom(x_dbm_ij, num, den);
        // Build skeleton DB constraint (having the right space dimension).
        db_expr = zero_expr;
        if (i > 0)
          db_expr += Variable(i-1);
        if (j > 0)
          db_expr -= Variable(j-1);
        if (den != 1)
          db_expr *= den;
        db_expr += num;
        if (x_dbm_ij >= y_dbm_i[j])
          env_cs.insert(db_expr >= 0);
        else {
          db_expr += eps;
          x_cs_removed.insert(db_expr == 0);
        }
      }
      if (!y_red_i[j]) {
        const N& y_dbm_ij = y_dbm_i[j];
        const N& x_dbm_ij = x_dbm_i[j];
        assert(!is_plus_infinity(y_dbm_ij));
        numer_denom(y_dbm_ij, num, den);
        // Build skeleton DB constraint (having the right space dimension).
        db_expr = zero_expr;
        if (i > 0)
          db_expr += Variable(i-1);
        if (j > 0)
          db_expr -= Variable(j-1);
        if (den != 1)
          db_expr *= den;
        db_expr += num;
        if (y_dbm_ij >= x_dbm_ij) {
          // Check if same constraint was added when considering x_dbm_ij.
          if (!x_red_i[j] && x_dbm_ij == y_dbm_ij)
            continue;
          env_cs.insert(db_expr >= 0);
        }
        else {
          db_expr += eps;
          y_cs_removed.insert(db_expr == 0);
        }
      }
    }
  }

  if (x_cs_removed.empty())
    // No constraint of x was removed: y is included in x.
    return true;
  if (y_cs_removed.empty()) {
    // No constraint of y was removed: x is included in y.
    *this = y;
    return true;
  }

  // In preparation to Step 4: build the common part of LP problems,
  // i.e., the constraints corresponding to env(x,y),
  // where the additional space dimension (eps) has to be maximised.
  MIP_Problem env_lp(x_space_dim + 1, env_cs, eps, MAXIMIZATION);
  // Pre-solve `env_lp' to later exploit incrementality.
  env_lp.solve();
  assert(env_lp.solve() != UNFEASIBLE_MIP_PROBLEM);

  // Implementing loop in Steps 3-6.
  for (Constraint_System::const_iterator i = x_cs_removed.begin(),
         i_end = x_cs_removed.end(); i != i_end; ++i) {
    MIP_Problem lp_i(env_lp);
    lp_i.add_constraint(*i);
    // Pre-solve to exploit incrementality.
    if (lp_i.solve() == UNFEASIBLE_MIP_PROBLEM)
      continue;
    for (Constraint_System::const_iterator j = y_cs_removed.begin(),
           j_end = y_cs_removed.end(); j != j_end; ++j) {
      MIP_Problem lp_ij(lp_i);
      lp_ij.add_constraint(*j);
      // Solve and check for a positive optimal value.
      switch (lp_ij.solve()) {
      case UNFEASIBLE_MIP_PROBLEM:
        // CHECKME: is the following actually impossible?
        throw std::runtime_error("PPL internal error");
      case UNBOUNDED_MIP_PROBLEM:
        return false;
      case OPTIMIZED_MIP_PROBLEM:
        lp_ij.optimal_value(num, den);
        if (num > 0)
          return false;
        break;
      }
    }
  }

  // The upper bound of x and y is indeed exact.
  upper_bound_assign(y);
  assert(OK());
  return true;
}

template <typename T>
bool
BD_Shape<T>::BHZ09_upper_bound_assign_if_exact(const BD_Shape& y) {
  // FIXME, CHECKME: what about inexact computations?

  // Declare a const reference to *this (to avoid accidental modifications).
  const BD_Shape& x = *this;
  const dimension_type x_space_dim = x.space_dimension();

  // Private method: the caller must ensure the following.
  assert(x_space_dim == y.space_dimension());

  // The zero-dim case is trivial.
  if (x_space_dim == 0) {
    upper_bound_assign(y);
    return true;
  }
  // If `x' or `y' is (known to be) empty, the upper bound is exact.
  if (x.marked_empty()) {
    *this = y;
    return true;
  }
  else if (y.is_empty())
    return true;
  else if (x.is_empty()) {
    *this = y;
    return true;
  }

  // Here both `x' and `y' are known to be non-empty.
  x.shortest_path_reduction_assign();
  y.shortest_path_reduction_assign();
  assert(x.marked_shortest_path_closed());
  assert(y.marked_shortest_path_closed());
  // Pre-compute the upper bound of `x' and `y'.
  BD_Shape<T> ub(x);
  ub.upper_bound_assign(y);

  PPL_DIRTY_TEMP(N, lhs);
  PPL_DIRTY_TEMP(N, rhs);
  PPL_DIRTY_TEMP(N, temp_zero);
  assign_r(temp_zero, 0, ROUND_NOT_NEEDED);

  for (dimension_type i = x_space_dim + 1; i-- > 0; ) {
    const DB_Row<N>& x_i = x.dbm[i];
    const Bit_Row& x_red_i = x.redundancy_dbm[i];
    const DB_Row<N>& y_i = y.dbm[i];
    const DB_Row<N>& ub_i = ub.dbm[i];
    for (dimension_type j = x_space_dim + 1; j-- > 0; ) {
      // Check redundancy of x_i_j.
      if (x_red_i[j])
        continue;
      // By non-redundancy, we know that i != j.
      assert(i != j);
      const N& x_i_j = x_i[j];
      if (x_i_j < y_i[j]) {
        for (dimension_type k = x_space_dim + 1; k-- > 0; ) {
          const DB_Row<N>& x_k = x.dbm[k];
          const DB_Row<N>& y_k = y.dbm[k];
          const Bit_Row& y_red_k = y.redundancy_dbm[k];
          const DB_Row<N>& ub_k = ub.dbm[k];
          const N& ub_k_j = (k == j) ? temp_zero : ub_k[j];
          for (dimension_type ell = x_space_dim + 1; ell-- > 0; ) {
            // Check redundancy of y_k_ell.
            if (y_red_k[ell])
              continue;
            // By non-redundancy, we know that k != ell.
            assert(k != ell);
            const N& y_k_ell = y_k[ell];
            if (y_k_ell < x_k[ell]) {
              // The first condition in BHZ09 theorem holds;
              // now check for the second condition.
              add_assign_r(lhs, x_i_j, y_k_ell, ROUND_UP);
              const N& ub_i_ell = (i == ell) ? temp_zero : ub_i[ell];
              add_assign_r(rhs, ub_i_ell, ub_k_j, ROUND_UP);
              if (lhs < rhs)
                return false;
            }
          }
        }
      }
    }
  }
  // The upper bound of x and y is indeed exact.
  swap(ub);
  assert(OK());
  return true;
}

template <typename T>
void
BD_Shape<T>::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("difference_assign(y)", y);

  BD_Shape new_bd_shape(space_dim, EMPTY);

  BD_Shape& x = *this;

  x.shortest_path_closure_assign();
  // The difference of an empty bounded difference shape
  // and of a bounded difference shape `p' is empty.
  if (x.marked_empty())
    return;
  y.shortest_path_closure_assign();
  // The difference of a bounded difference shape `p'
  // and an empty bounded difference shape is `p'.
  if (y.marked_empty())
    return;

  // If both bounded difference shapes 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 bounded difference shape `x' is included
    // in the bounded difference shape defined by `c',
    // then `c' _must_ be skipped, as adding its complement to `x'
    // would result in the empty bounded difference shape,
    // 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);
    z.add_constraint(e <= 0);
    if (!z.is_empty())
      new_bd_shape.upper_bound_assign(z);
    if (c.is_equality()) {
      z = x;
      z.add_constraint(e >= 0);
      if (!z.is_empty())
        new_bd_shape.upper_bound_assign(z);
    }
  }
  *this = new_bd_shape;
  assert(OK());
}

template <typename T>
bool
BD_Shape<T>::simplify_using_context_assign(const BD_Shape& y) {
  BD_Shape& x = *this;
  const dimension_type dim = x.space_dimension();
  // Dimension-compatibility check.
  if (dim != y.space_dimension())
    throw_dimension_incompatible("simplify_using_context_assign(y)", y);

  // Filter away the zero-dimensional case.
  if (dim == 0) {
    if (y.marked_empty()) {
      x.set_zero_dim_univ();
      return false;
    }
    else
      return !x.marked_empty();
  }

  // Filter away the case where `x' contains `y'
  // (this subsumes the case when `y' is empty).
  y.shortest_path_closure_assign();
  if (x.contains(y)) {
    BD_Shape<T> res(dim, UNIVERSE);
    x.swap(res);
    return false;
  }

  // Filter away the case where `x' is empty.
  x.shortest_path_closure_assign();
  if (x.marked_empty()) {
    // Search for a constraint of `y' that is not a tautology.
    dimension_type i;
    dimension_type j;
    // Prefer unary constraints.
    i = 0;
    const DB_Row<N>& y_dbm_0 = y.dbm[0];
    for (j = 1; j <= dim; ++j) {
      if (!is_plus_infinity(y_dbm_0[j]))
        // FIXME: if N is a float or bounded integer type, then
        // we also need to check that we are actually able to construct
        // a constraint inconsistent wrt this one.
        goto found;
    }
    j = 0;
    for (i = 1; i <= dim; ++i) {
      if (!is_plus_infinity(y.dbm[i][0]))
        // FIXME: if N is a float or bounded intefer type, then
        // we also need to check that we are actually able to construct
        // a constraint inconsistent wrt this one.
        goto found;
    }
    // Then search binary constraints.
    for (i = 1; i <= dim; ++i) {
      const DB_Row<N>& y_dbm_i = y.dbm[i];
      for (j = 1; j <= dim; ++j)
        if (!is_plus_infinity(y_dbm_i[j]))
          // FIXME: if N is a float or bounded intefer type, then
          // we also need to check that we are actually able to construct
          // a constraint inconsistent wrt this one.
          goto found;
    }
    // Not found: we were not able to build a constraint contradicting
    // one of the constraints in `y': `x' cannot be enlarged.
    return false;

  found:
    // Found: build a new BDS contradicting the constraint found.
    assert(i <= dim && j <= dim && (i > 0 || j > 0));
    BD_Shape<T> res(dim, UNIVERSE);
    PPL_DIRTY_TEMP(N, tmp);
    assign_r(tmp, 1, ROUND_UP);
    add_assign_r(tmp, tmp, y.dbm[i][j], ROUND_UP);
    assert(!is_plus_infinity(tmp));
    // CHECKME: round down is really meant.
    neg_assign_r(res.dbm[j][i], tmp, ROUND_DOWN);
    x.swap(res);
    return false;
  }

  // Here `x' and `y' are not empty and shortest-path closed;
  // also, `x' does not contain `y'.
  // Let `target' be the intersection of `x' and `y'.
  BD_Shape<T> target = x;
  target.intersection_assign(y);
  const bool bool_result = !target.is_empty();

  // Compute a reduced dbm for `x' and ...
  x.shortest_path_reduction_assign();
  // ... count the non-redundant constraints.
  dimension_type x_num_nonredundant = (dim+1)*(dim+1);
  for (dimension_type i = dim + 1; i-- > 0; )
    x_num_nonredundant -= x.redundancy_dbm[i].count_ones();
  assert(x_num_nonredundant > 0);

  // Let `yy' be a copy of `y': we will keep adding to `yy'
  // the non-redundant constraints of `x',
  // stopping as soon as `yy' becomes equal to `target'.
  BD_Shape<T> yy = y;

  // The constraints added to `yy' will be recorded in `res' ...
  BD_Shape<T> res(dim, UNIVERSE);
  // ... and we will count them too.
  dimension_type res_num_nonredundant = 0;

  // Compute leader information for `x'.
  std::vector<dimension_type> x_leaders;
  x.compute_leaders(x_leaders);

  // First go through the unary equality constraints.
  const DB_Row<N>& x_dbm_0 = x.dbm[0];
  DB_Row<N>& yy_dbm_0 = yy.dbm[0];
  DB_Row<N>& res_dbm_0 = res.dbm[0];
  for (dimension_type j = 1; j <= dim; ++j) {
    // Unary equality constraints are encoded in entries dbm_0j and dbm_j0
    // provided index j has special variable index 0 as its leader.
    if (x_leaders[j] != 0)
      continue;
    assert(!is_plus_infinity(x_dbm_0[j]));
    if (x_dbm_0[j] < yy_dbm_0[j]) {
      res_dbm_0[j] = x_dbm_0[j];
      ++res_num_nonredundant;
      // Tighten context `yy' using the newly added constraint.
      yy_dbm_0[j] = x_dbm_0[j];
      yy.reset_shortest_path_closed();
    }
    assert(!is_plus_infinity(x.dbm[j][0]));
    if (x.dbm[j][0] < yy.dbm[j][0]) {
      res.dbm[j][0] = x.dbm[j][0];
      ++res_num_nonredundant;
      // Tighten context `yy' using the newly added constraint.
      yy.dbm[j][0] = x.dbm[j][0];
      yy.reset_shortest_path_closed();
    }
    // Restore shortest-path closure, if it was lost.
    if (!yy.marked_shortest_path_closed()) {
      Variable var_j(j-1);
      yy.incremental_shortest_path_closure_assign(var_j);
      if (target.contains(yy)) {
        // Target reached: swap `x' and `res' if needed.
        if (res_num_nonredundant < x_num_nonredundant) {
          res.reset_shortest_path_closed();
          x.swap(res);
        }
        return bool_result;
      }
    }
  }

  // Go through the binary equality constraints.
  // Note: no need to consider the case i == 1.
  for (dimension_type i = 2; i <= dim; ++i) {
    const dimension_type j = x_leaders[i];
    if (j == i || j == 0)
      continue;
    assert(!is_plus_infinity(x.dbm[i][j]));
    if (x.dbm[i][j] < yy.dbm[i][j]) {
      res.dbm[i][j] = x.dbm[i][j];
      ++res_num_nonredundant;
      // Tighten context `yy' using the newly added constraint.
      yy.dbm[i][j] = x.dbm[i][j];
      yy.reset_shortest_path_closed();
    }
    assert(!is_plus_infinity(x.dbm[j][i]));
    if (x.dbm[j][i] < yy.dbm[j][i]) {
      res.dbm[j][i] = x.dbm[j][i];
      ++res_num_nonredundant;
      // Tighten context `yy' using the newly added constraint.
      yy.dbm[j][i] = x.dbm[j][i];
      yy.reset_shortest_path_closed();
    }
    // Restore shortest-path closure, if it was lost.
    if (!yy.marked_shortest_path_closed()) {
      Variable var_j(j-1);
      yy.incremental_shortest_path_closure_assign(var_j);
      if (target.contains(yy)) {
        // Target reached: swap `x' and `res' if needed.
        if (res_num_nonredundant < x_num_nonredundant) {
          res.reset_shortest_path_closed();
          x.swap(res);
        }
        return bool_result;
      }
    }
  }

  // Finally go through the (proper) inequality constraints:
  // both indices i and j should be leaders.
  for (dimension_type i = 0; i <= dim; ++i) {
    if (i != x_leaders[i])
      continue;
    const DB_Row<N>& x_dbm_i = x.dbm[i];
    const Bit_Row& x_redundancy_dbm_i = x.redundancy_dbm[i];
    DB_Row<N>& yy_dbm_i = yy.dbm[i];
    DB_Row<N>& res_dbm_i = res.dbm[i];
    for (dimension_type j = 0; j <= dim; ++j) {
      if (j != x_leaders[j] || x_redundancy_dbm_i[j])
        continue;
      N& yy_dbm_ij = yy_dbm_i[j];
      const N& x_dbm_ij = x_dbm_i[j];
      if (x_dbm_ij < yy_dbm_ij) {
        res_dbm_i[j] = x_dbm_ij;
        ++res_num_nonredundant;
        // Tighten context `yy' using the newly added constraint.
        yy_dbm_ij = x_dbm_ij;
        yy.reset_shortest_path_closed();
        assert(i > 0 || j > 0);
        Variable var((i > 0 ? i : j) - 1);
        yy.incremental_shortest_path_closure_assign(var);
        if (target.contains(yy)) {
          // Target reached: swap `x' and `res' if needed.
          if (res_num_nonredundant < x_num_nonredundant) {
            res.reset_shortest_path_closed();
            x.swap(res);
          }
          return bool_result;
        }
      }
    }
  }
  // This point should be unreachable.
  throw std::runtime_error("PPL internal error");
}

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 bounded difference shape,
  // 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())
    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)
    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);
      }
      set_shortest_path_closed();
    }
    assert(OK());
    return;
  }

  // To project an n-dimension space bounded difference shape
  // 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())
    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;
  }

  const dimension_type old_space_dim = space_dimension();

  // Dimension-compatibility check.
  const dimension_type min_space_dim = to_be_removed.space_dimension();
  if (old_space_dim < min_space_dim)
    throw_dimension_incompatible("remove_space_dimensions(vs)", min_space_dim);

  // 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;
  }

  // Handle the case of an empty BD_Shape.
  if (marked_empty()) {
    dbm.resize_no_copy(new_space_dim + 1);
    assert(OK());
    return;
  }

  // Shortest-path closure is maintained.
  // TODO: see whether reduction can be (efficiently!) maintained too.
  if (marked_shortest_path_reduced())
    reset_shortest_path_reduced();

  // For each variable to remove, we fill the corresponding column and
  // row by shifting respectively left and above those
  // columns and rows, that will not be removed.
  Variables_Set::const_iterator tbr = to_be_removed.begin();
  Variables_Set::const_iterator tbr_end = to_be_removed.end();
  dimension_type dst = *tbr + 1;
  dimension_type src = dst + 1;
  for (++tbr; tbr != tbr_end; ++tbr) {
    const dimension_type tbr_next = *tbr + 1;
    // All other columns and rows are moved respectively to the left
    // and above.
    while (src < tbr_next) {
      std::swap(dbm[dst], dbm[src]);
      for (dimension_type i = old_space_dim + 1; i-- > 0; ) {
        DB_Row<N>& dbm_i = dbm[i];
        assign_or_swap(dbm_i[dst], dbm_i[src]);
      }
      ++dst;
      ++src;
    }
    ++src;
  }

  // Moving the remaining rows and columns.
  while (src <= old_space_dim) {
    std::swap(dbm[dst], dbm[src]);
    for (dimension_type i = old_space_dim + 1; i-- > 0; ) {
      DB_Row<N>& dbm_i = dbm[i];
      assign_or_swap(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 Partial_Function>
void
BD_Shape<T>::map_space_dimensions(const Partial_Function& 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);
    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 bounded difference shape.
  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())
    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.
  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)) {
      assign_or_swap(x_0[new_j + 1], dbm_0[j]);
      assign_or_swap(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)) {
      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;
          assign_or_swap(x_new_i[new_j], dbm_i[j]);
          assign_or_swap(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 bounded difference shapes is empty,
  // the intersection is empty.
  if (marked_empty())
    return;
  if (y.marked_empty()) {
    set_empty();
    return;
  }

  // If both bounded difference shapes 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 bounded difference shapes 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())
    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 bounded difference shapes 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
          assign_r(dbm_ij, PLUS_INFINITY, ROUND_NOT_NEEDED);
      }
    }
  }
  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 {
  const dimension_type cs_space_dim = cs.space_dimension();
  // Private method: the caller has to ensure the following.
  assert(cs_space_dim <= space_dimension());

  shortest_path_closure_assign();
  bool changed = false;
  PPL_DIRTY_TEMP_COEFFICIENT(coeff);
  PPL_DIRTY_TEMP_COEFFICIENT(minus_c_term);
  PPL_DIRTY_TEMP(N, d);
  PPL_DIRTY_TEMP(N, d1);
  for (Constraint_System::const_iterator cs_i = cs.begin(),
         cs_end = cs.end(); cs_i != cs_end; ++cs_i) {
    const Constraint& c = *cs_i;
    dimension_type num_vars = 0;
    dimension_type i = 0;
    dimension_type j = 0;
    // 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 bool negative = (coeff < 0);
      const N& x = negative ? dbm[i][j] : dbm[j][i];
      const N& y = negative ? dbm[j][i] : dbm[i][j];
      DB_Matrix<N>& ls_dbm = limiting_shape.dbm;
      N& ls_x = negative ? ls_dbm[i][j] : ls_dbm[j][i];
      N& ls_y = negative ? ls_dbm[j][i] : ls_dbm[i][j];
      if (negative)
        neg_assign(coeff);
      // Compute the bound for `x', rounding towards plus infinity.
      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.
          neg_assign(minus_c_term, c.inhomogeneous_term());
          div_round_up(d1, minus_c_term, coeff);
          if (y <= d1)
	    if((ls_x >= d && ls_y > d1) || (ls_x > d && ls_y >= d1)) {
	      ls_x = d;
	      ls_y = d1;
	      changed = true;
          }
        }
      }
    }
  }

  // In general, adding a constraint does not preserve the shortest-path
  // closure of the bounded difference shape.
  if (changed && limiting_shape.marked_shortest_path_closed())
    limiting_shape.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_generic("limited_CC76_extrapolation_assign(y, cs)",
                  "cs is space_dimension incompatible");

  // Strict inequalities not allowed.
  if (cs.has_strict_inequalities())
    throw_generic("limited_CC76_extrapolation_assign(y, cs)",
                  "cs has strict inequalities");

  // 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);
}

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 Bit_Row& 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)
        assign_r(dbm_ij, PLUS_INFINITY, ROUND_NOT_NEEDED);
    }
  }
  // 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.
  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_generic("limited_BHMZ05_extrapolation_assign(y, cs)",
                  "cs is space-dimension incompatible");

  // Strict inequalities are not allowed.
  if (cs.has_strict_inequalities())
    throw_generic("limited_BHMZ05_extrapolation_assign(y, cs)",
                  "cs has strict inequalities");

  // 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);
}

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 bounded difference shapes 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())
    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& ub_v) {
  assert(sc_den > 0);
  assert(!is_plus_infinity(ub_v));
  // 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)'.
  PPL_DIRTY_TEMP0(mpq_class, mpq_sc_den);
  assign_r(mpq_sc_den, sc_den, ROUND_NOT_NEEDED);
  const DB_Row<N>& dbm_0 = dbm[0];
  // Speculative allocation of temporaries to be used in the following loop.
  PPL_DIRTY_TEMP0(mpq_class, minus_lb_u);
  PPL_DIRTY_TEMP0(mpq_class, q);
  PPL_DIRTY_TEMP0(mpq_class, ub_u);
  PPL_DIRTY_TEMP(N, up_approx);
  // 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], ub_v, 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.,
            // `ub_v + (-lb_u) - q * (ub_u + (-lb_u))'.
            assign_r(minus_lb_u, dbm_u0, ROUND_NOT_NEEDED);
            assign_r(q, expr_u, ROUND_NOT_NEEDED);
            div_assign_r(q, q, mpq_sc_den, ROUND_NOT_NEEDED);
            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);
            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], ub_v, 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& minus_lb_v) {
  assert(sc_den > 0);
  assert(!is_plus_infinity(minus_lb_v));
  // 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'.
  PPL_DIRTY_TEMP0(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];
  // Speculative allocation of temporaries to be used in the following loop.
  PPL_DIRTY_TEMP0(mpq_class, ub_u);
  PPL_DIRTY_TEMP0(mpq_class, q);
  PPL_DIRTY_TEMP0(mpq_class, minus_lb_u);
  PPL_DIRTY_TEMP(N, up_approx);
  // 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], minus_lb_v, 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)) + minus_lb_v'.
            assign_r(ub_u, dbm_0u, ROUND_NOT_NEEDED);
            assign_r(q, expr_u, ROUND_NOT_NEEDED);
            div_assign_r(q, q, mpq_sc_den, ROUND_NOT_NEEDED);
            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);
            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, minus_lb_v, ROUND_UP);
          }
        }
      }
    }
}

template <typename T>
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; ) {
    assign_r(dbm_v[i], PLUS_INFINITY, ROUND_NOT_NEEDED);
    assign_r(dbm[i][v], PLUS_INFINITY, ROUND_NOT_NEEDED);
  }
}

template <typename T>
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) {
    assign_r(dbm_v[i], PLUS_INFINITY, ROUND_NOT_NEEDED);
    assign_r(dbm[i][v], PLUS_INFINITY, ROUND_NOT_NEEDED);
  }
}

template <typename T>
void
BD_Shape<T>::unconstrain(const Variable var) {
  // Dimension-compatibility check.
  const dimension_type dim = var.id();
  if (space_dimension() < dim)
    throw_dimension_incompatible("unconstrain(var)", dim);

  // Shortest-path closure is necessary to detect emptiness
  // and all (possibly implicit) constraints.
  shortest_path_closure_assign();

  // If the shape is empty, this is a no-op.
  if (marked_empty())
    return;

  forget_all_dbm_constraints(dim+1);
  // Shortest-path closure is preserved, but not reduction.
  reset_shortest_path_reduced();
  assert(OK());
}

template <typename T>
void
BD_Shape<T>::unconstrain(const Variables_Set& to_be_unconstrained) {
  // The cylindrification wrt no dimensions is a no-op.
  // This case captures the only legal cylindrification in a 0-dim space.
  if (to_be_unconstrained.empty())
    return;

  // Dimension-compatibility check.
  const dimension_type min_space_dim = to_be_unconstrained.space_dimension();
  if (space_dimension() < min_space_dim)
    throw_dimension_incompatible("unconstrain(vs)", min_space_dim);

  // Shortest-path closure is necessary to detect emptiness
  // and all (possibly implicit) constraints.
  shortest_path_closure_assign();

  // If the shape is empty, this is a no-op.
  if (marked_empty())
    return;

  for (Variables_Set::const_iterator tbu = to_be_unconstrained.begin(),
         tbu_end = to_be_unconstrained.end(); tbu != tbu_end; ++tbu)
    forget_all_dbm_constraints(*tbu + 1);
  // Shortest-path closure is preserved, but not reduction.
  reset_shortest_path_reduced();
  assert(OK());
}

template <typename T>
void
BD_Shape<T>::refine(const Variable var,
                    const Relation_Symbol relsym,
                    const Linear_Expression& expr,
                    Coefficient_traits::const_reference denominator) {
  assert(denominator != 0);
  const dimension_type expr_space_dim = expr.space_dimension();
  assert(space_dimension() >= expr_space_dim);
  const dimension_type v = var.id() + 1;
  assert(v <= space_dimension());
  assert(expr.coefficient(var) == 0);
  assert(relsym != LESS_THAN && relsym != GREATER_THAN);

  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;
    }

  // Since we are only able to record bounded differences, we can
  // precisely deal with the case of a single variable only if its
  // coefficient (taking into account the denominator) is 1.
  // If this is not the case, we fall back to the general case
  // so as to over-approximate the constraint.
  if (t == 1 && expr.coefficient(Variable(w-1)) != denominator)
    t = 2;

  // 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 != v' and `a == denominator';
  // - If t == 2, the `expr' is of the general form.
  const DB_Row<N>& dbm_0 = dbm[0];
  PPL_DIRTY_TEMP_COEFFICIENT(minus_den);
  neg_assign(minus_den, denominator);

  if (t == 0) {
    // Case 1: expr == b.
    switch (relsym) {
    case EQUAL:
      // Add the constraint `var == b/denominator'.
      add_dbm_constraint(0, v, b, denominator);
      add_dbm_constraint(v, 0, b, minus_den);
      break;
    case LESS_OR_EQUAL:
      // Add the constraint `var <= b/denominator'.
      add_dbm_constraint(0, v, b, denominator);
      break;
    case GREATER_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");
    }
    return;
  }

  if (t == 1) {
    // Case 2: expr == a*w + b, w != v, a == denominator.
    assert(expr.coefficient(Variable(w-1)) == denominator);
    PPL_DIRTY_TEMP(N, d);
    switch (relsym) {
    case EQUAL:
      // Add the new constraint `v - w <= b/denominator'.
      div_round_up(d, b, denominator);
      add_dbm_constraint(w, v, d);
      // Add the new constraint `v - w >= b/denominator',
      // i.e., `w - v <= -b/denominator'.
      div_round_up(d, b, minus_den);
      add_dbm_constraint(v, w, d);
      break;
    case LESS_OR_EQUAL:
      // Add the new constraint `v - w <= b/denominator'.
      div_round_up(d, b, denominator);
      add_dbm_constraint(w, v, d);
      break;
    case GREATER_OR_EQUAL:
      // Add the new constraint `v - w >= b/denominator',
      // i.e., `w - v <= -b/denominator'.
      div_round_up(d, b, minus_den);
      add_dbm_constraint(v, w, d);
      break;
    default:
      // We already dealt with the other cases.
      throw std::runtime_error("PPL internal error");
    }
    return;
  }

  // Here t == 2, so that either
  // expr == a_1*x_1 + a_2*x_2 + ... + a_n*x_n + b, where n >= 2, or
  // expr == a*w + b, w != v and a != denominator.
  const bool is_sc = (denominator > 0);
  PPL_DIRTY_TEMP_COEFFICIENT(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;

  PPL_DIRTY_TEMP(N, sum);
  // Indices of the variables that are unbounded in `this->dbm'.
  PPL_UNINITIALIZED(dimension_type, pinf_index);
  // Number of unbounded variables found.
  dimension_type pinf_count = 0;

  // Speculative allocation of temporaries that are used in most
  // of the computational traces starting from this point (also loops).
  PPL_DIRTY_TEMP_COEFFICIENT(minus_sc_i);
  PPL_DIRTY_TEMP(N, coeff_i);

  switch (relsym) {
  case EQUAL:
    {
      PPL_DIRTY_TEMP(N, neg_sum);
      // Indices of the variables that are unbounded in `this->dbm'.
      PPL_UNINITIALIZED(dimension_type, neg_pinf_index);
      // Number of unbounded variables found.
      dimension_type neg_pinf_count = 0;

      // 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);
      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 `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;
        if (sign_i > 0) {
          assign_r(coeff_i, sc_i, ROUND_UP);
          // Approximating `sc_expr'.
          if (pinf_count <= 1) {
            const N& approx_i = dbm_0[i];
            if (!is_plus_infinity(approx_i))
              add_mul_assign_r(sum, coeff_i, approx_i, ROUND_UP);
            else {
              ++pinf_count;
              pinf_index = i;
            }
          }
          // Approximating `-sc_expr'.
          if (neg_pinf_count <= 1) {
            const N& approx_minus_i = dbm[i][0];
            if (!is_plus_infinity(approx_minus_i))
              add_mul_assign_r(neg_sum, coeff_i, approx_minus_i, ROUND_UP);
            else {
              ++neg_pinf_count;
              neg_pinf_index = i;
            }
          }
        }
        else if (sign_i < 0) {
          neg_assign(minus_sc_i, sc_i);
          // Note: using temporary named `coeff_i' to store -coeff_i.
          assign_r(coeff_i, minus_sc_i, ROUND_UP);
          // Approximating `sc_expr'.
          if (pinf_count <= 1) {
            const N& approx_minus_i = dbm[i][0];
            if (!is_plus_infinity(approx_minus_i))
              add_mul_assign_r(sum, coeff_i, approx_minus_i, ROUND_UP);
            else {
              ++pinf_count;
              pinf_index = i;
            }
          }
          // Approximating `-sc_expr'.
          if (neg_pinf_count <= 1) {
            const N& approx_i = dbm_0[i];
            if (!is_plus_infinity(approx_i))
              add_mul_assign_r(neg_sum, coeff_i, approx_i, ROUND_UP);
            else {
              ++neg_pinf_count;
              neg_pinf_index = i;
            }
          }
        }
      }
      // Return immediately if no approximation could be computed.
      if (pinf_count > 1 && neg_pinf_count > 1) {
        assert(OK());
        return;
      }

      // In the following, shortest-path closure will be definitely lost.
      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.
      PPL_DIRTY_TEMP(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 (pinf_count <= 1) {
        // Compute quotient (if needed).
        if (down_sc_den != 1)
          div_assign_r(sum, sum, down_sc_den, ROUND_UP);
        // Add the upper bound constraint, if meaningful.
        if (pinf_count == 0) {
          // Add the constraint `v <= sum'.
          dbm[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
          // Here `pinf_count == 1'.
          if (pinf_index != v
              && sc_expr.coefficient(Variable(pinf_index-1)) == sc_den)
            // Add the constraint `v - pinf_index <= sum'.
            dbm[pinf_index][v] = sum;
      }

      // 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];
          dbm_v[0] = neg_sum;
          // 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'.
            dbm[v][neg_pinf_index] = neg_sum;
      }
    }
    break;

  case LESS_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 = 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;
      }
      if (sign_i > 0)
        assign_r(coeff_i, sc_i, ROUND_UP);
      else {
        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.
      PPL_DIRTY_TEMP(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 (expr.coefficient(Variable(pinf_index-1)) == denominator)
        // Add the constraint `v - pinf_index <= sum'.
        add_dbm_constraint(pinf_index, v, sum);
      break;

  case GREATER_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 = 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[i][0] : dbm_0[i];
      if (is_plus_infinity(approx_i)) {
        if (++pinf_count > 1)
          break;
        pinf_index = i;
        continue;
      }
      if (sign_i > 0)
        assign_r(coeff_i, sc_i, ROUND_UP);
      else {
        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.
      PPL_DIRTY_TEMP(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");
  }

  assert(OK());
}

template <typename T>
void
BD_Shape<T>::affine_image(const Variable var,
                          const Linear_Expression& expr,
                          Coefficient_traits::const_reference denominator) {
  // 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.
  PPL_DIRTY_TEMP_COEFFICIENT(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())
      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'.
            PPL_DIRTY_TEMP(N, d);
            div_round_up(d, b, denominator);
            PPL_DIRTY_TEMP(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.
          reset_shortest_path_closed();
          if (b != 0) {
            // Translate the unary constraints on `var',
            // adding or subtracting the value `b/denominator'.
            PPL_DIRTY_TEMP(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);
            PPL_DIRTY_TEMP(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())
          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'.
            PPL_DIRTY_TEMP(N, d);
            div_round_up(d, b, denominator);
            add_assign_r(dbm[0][v], d, dbm_w0, ROUND_UP);
            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'.
            PPL_DIRTY_TEMP(N, c);
            div_round_up(c, b, minus_den);
            add_assign_r(dbm[v][0], dbm_0w, c, ROUND_UP);
            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);
  PPL_DIRTY_TEMP_COEFFICIENT(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;

  PPL_DIRTY_TEMP(N, pos_sum);
  PPL_DIRTY_TEMP(N, neg_sum);
  // Indices of the variables that are unbounded in `this->dbm'.
  PPL_UNINITIALIZED(dimension_type, pos_pinf_index);
  PPL_UNINITIALIZED(dimension_type, neg_pinf_index);
  // 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'.
  const DB_Row<N>& dbm_0 = dbm[0];
  // Speculative allocation of temporaries to be used in the following loop.
  PPL_DIRTY_TEMP(N, coeff_i);
  PPL_DIRTY_TEMP_COEFFICIENT(minus_sc_i);
  // 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) {
      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) {
      neg_assign(minus_sc_i, sc_i);
      // Note: using temporary named `coeff_i' to store -coeff_i.
      assign_r(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, 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, 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())
    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.
  reset_shortest_path_closed();

  // Exploit the upper approximation, if possible.
  if (pos_pinf_count <= 1) {
    // Compute quotient (if needed).
    if (sc_den != 1) {
      // 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.
      PPL_DIRTY_TEMP(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(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'.
      dbm[0][v] = pos_sum;
      // 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'.
        dbm[pos_pinf_index][v] = pos_sum;
  }

  // Exploit the lower approximation, if possible.
  if (neg_pinf_count <= 1) {
    // Compute quotient (if needed).
    if (sc_den != 1) {
      // 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.
      PPL_DIRTY_TEMP(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(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];
      dbm_v[0] = neg_sum;
      // 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'.
        dbm[v][neg_pinf_index] = neg_sum;
  }

  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 bounded difference shapes.
  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())
      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, denominator*var - b, a);
      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())
          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())
      reset_shortest_path_reduced();
  }
  assert(OK());
}

template <typename T>
void
BD_Shape<T>
::bounded_affine_image(const Variable var,
                       const Linear_Expression& lb_expr,
                       const Linear_Expression& ub_expr,
                       Coefficient_traits::const_reference denominator) {
  // The denominator cannot be zero.
  if (denominator == 0)
    throw_generic("bounded_affine_image(v, lb, ub, d)", "d == 0");

  // Dimension-compatibility checks.
  // `var' should be one of the dimensions of the BD_Shape.
  const dimension_type bds_space_dim = space_dimension();
  const dimension_type v = var.id() + 1;
  if (v > bds_space_dim)
    throw_dimension_incompatible("bounded_affine_image(v, lb, ub, d)",
                                 "v", var);
  // The dimension of `lb_expr' and `ub_expr' should not be
  // greater than the dimension of `*this'.
  const dimension_type lb_space_dim = lb_expr.space_dimension();
  if (bds_space_dim < lb_space_dim)
    throw_dimension_incompatible("bounded_affine_image(v, lb, ub)",
                                 "lb", lb_expr);
  const dimension_type ub_space_dim = ub_expr.space_dimension();
  if (bds_space_dim < ub_space_dim)
    throw_dimension_incompatible("bounded_affine_image(v, lb, ub)",
                                 "ub", ub_expr);

  // Any image of an empty BDS is empty.
  shortest_path_closure_assign();
  if (marked_empty())
    return;

  const Coefficient& b = ub_expr.inhomogeneous_term();
  // Number of non-zero coefficients in `ub_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 `ub_expr', if any.
  dimension_type w = 0;
  // Get information about the number of non-zero coefficients in `expr'.
  for (dimension_type i = ub_space_dim; i-- > 0; )
    if (ub_expr.coefficient(Variable(i)) != 0) {
      if (t++ == 1)
        break;
      else
        w = i+1;
    }

  // Now we know the form of `ub_expr':
  // - If t == 0, then ub_expr == b, with `b' a constant;
  // - If t == 1, then ub_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 `ub_expr' is of the general form.
  PPL_DIRTY_TEMP_COEFFICIENT(minus_den);
  neg_assign(minus_den, denominator);

  if (t == 0) {
    // Case 1: ub_expr == b.
    generalized_affine_image(var,
                             GREATER_OR_EQUAL,
                             lb_expr,
                             denominator);
    // Add the constraint `var <= b/denominator'.
    add_dbm_constraint(0, v, b, denominator);
    assert(OK());
    return;
  }

  if (t == 1) {
    // Value of the one and only non-zero coefficient in `ub_expr'.
    const Coefficient& a = ub_expr.coefficient(Variable(w-1));
    if (a == denominator || a == minus_den) {
      // Case 2: expr == a*w + b, with a == +/- denominator.
      if (w == v) {
        // Here `var' occurs in `ub_expr'.
        // To ease the computation, we add an additional dimension.
        const Variable new_var = Variable(bds_space_dim);
        add_space_dimensions_and_embed(1);
        // Constrain the new dimension to be equal to `ub_expr'.
        affine_image(new_var, ub_expr, denominator);
        // NOTE: enforce shortest-path closure for precision.
        shortest_path_closure_assign();
        assert(!marked_empty());
        // Apply the affine lower bound.
        generalized_affine_image(var,
                                 GREATER_OR_EQUAL,
                                 lb_expr,
                                 denominator);
        // Now apply the affine upper bound, as recorded in `new_var'.
        add_constraint(var <= new_var);
        // Remove the temporarily added dimension.
        remove_higher_space_dimensions(bds_space_dim);
        return;
      }
      else {
        // Here `w != v', so that `expr' is of the form
        // +/-denominator * w + b.
        // Apply the affine lower bound.
        generalized_affine_image(var,
                                 GREATER_OR_EQUAL,
                                 lb_expr,
                                 denominator);
        if (a == denominator) {
          // Add the new constraint `v - w == b/denominator'.
          add_dbm_constraint(w, v, b, denominator);
        }
        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'.
            PPL_DIRTY_TEMP(N, d);
            div_round_up(d, b, denominator);
            add_assign_r(dbm[0][v], d, dbm_w0, ROUND_UP);
            reset_shortest_path_closed();
          }
        }
        assert(OK());
        return;
      }
    }
  }

  // General case.
  // Either t == 2, so that
  // ub_expr == a_1*x_1 + a_2*x_2 + ... + a_n*x_n + b, where n >= 2,
  // or t == 1, ub_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 `ub_expr' into `pos_sum'
  // taking into account the sign of `denominator'.
  const bool is_sc = (denominator > 0);
  PPL_DIRTY_TEMP_COEFFICIENT(minus_b);
  neg_assign(minus_b, b);
  const Coefficient& sc_b = is_sc ? b : minus_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 = -ub_expr;
  const Linear_Expression& sc_expr = is_sc ? ub_expr : minus_expr;

  PPL_DIRTY_TEMP(N, pos_sum);
  // Index of the variable that are unbounded in `this->dbm'.
  PPL_UNINITIALIZED(dimension_type, pos_pinf_index);
  // Number of unbounded variables found.
  dimension_type pos_pinf_count = 0;

  // Approximate the inhomogeneous term.
  assign_r(pos_sum, sc_b, ROUND_UP);

  // Approximate the homogeneous part of `sc_expr'.
  const DB_Row<N>& dbm_0 = dbm[0];
  // Speculative allocation of temporaries to be used in the following loop.
  PPL_DIRTY_TEMP(N, coeff_i);
  PPL_DIRTY_TEMP_COEFFICIENT(minus_sc_i);
  // 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) {
      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;
        }
      }
    }
    else if (sign_i < 0) {
      neg_assign(minus_sc_i, sc_i);
      // Note: using temporary named `coeff_i' to store -coeff_i.
      assign_r(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, coeff_i, up_approx_minus_i, ROUND_UP);
        else {
          ++pos_pinf_count;
          pos_pinf_index = i;
        }
      }
    }
  }
  // Apply the affine lower bound.
  generalized_affine_image(var,
                           GREATER_OR_EQUAL,
                           lb_expr,
                           denominator);
  // Return immediately if no approximation could be computed.
  if (pos_pinf_count > 1) {
    return;
  }

  // In the following, shortest-path closure will be definitely lost.
  reset_shortest_path_closed();

  // Exploit the upper approximation, if possible.
  if (pos_pinf_count <= 1) {
    // Compute quotient (if needed).
    if (sc_den != 1) {
      // 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.
      PPL_DIRTY_TEMP(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(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'.
      dbm[0][v] = pos_sum;
      // 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'.
        dbm[pos_pinf_index][v] = pos_sum;
  }
  assert(OK());
}

template <typename T>
void
BD_Shape<T>
::bounded_affine_preimage(const Variable var,
                          const Linear_Expression& lb_expr,
                          const Linear_Expression& ub_expr,
                          Coefficient_traits::const_reference denominator) {
  // The denominator cannot be zero.
  if (denominator == 0)
    throw_generic("bounded_affine_preimage(v, lb, ub, d)", "d == 0");

  // Dimension-compatibility checks.
  // `var' should be one of the dimensions of the BD_Shape.
  const dimension_type space_dim = space_dimension();
  const dimension_type v = var.id() + 1;
  if (v > space_dim)
    throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub, d)",
                                 "v", var);
  // The dimension of `lb_expr' and `ub_expr' should not be
  // greater than the dimension of `*this'.
  const dimension_type lb_space_dim = lb_expr.space_dimension();
  if (space_dim < lb_space_dim)
    throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub)",
                                 "lb", lb_expr);
  const dimension_type ub_space_dim = ub_expr.space_dimension();
  if (space_dim < ub_space_dim)
    throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub)",
                                 "ub", ub_expr);

  // Any preimage of an empty BDS is empty.
  shortest_path_closure_assign();
  if (marked_empty())
    return;

  if (ub_expr.coefficient(var) == 0) {
    refine(var, LESS_OR_EQUAL, ub_expr, denominator);
    generalized_affine_preimage(var, GREATER_OR_EQUAL,
                                lb_expr, denominator);
    return;
  }
  if (lb_expr.coefficient(var) == 0) {
    refine(var, GREATER_OR_EQUAL, lb_expr, denominator);
    generalized_affine_preimage(var, LESS_OR_EQUAL,
                                ub_expr, denominator);
    return;
  }

  const Coefficient& lb_expr_v = lb_expr.coefficient(var);
  // Here `var' occurs in `lb_expr' and `ub_expr'.
  // To ease the computation, we add an additional dimension.
  const Variable new_var = Variable(space_dim);
  add_space_dimensions_and_embed(1);
  const Linear_Expression lb_inverse
    = lb_expr - (lb_expr_v + denominator)*var;
  PPL_DIRTY_TEMP_COEFFICIENT(lb_inverse_den);
  neg_assign(lb_inverse_den, lb_expr_v);
  affine_image(new_var, lb_inverse, lb_inverse_den);
  shortest_path_closure_assign();
  assert(!marked_empty());
  generalized_affine_preimage(var, LESS_OR_EQUAL,
                              ub_expr, denominator);
  if (sgn(denominator) == sgn(lb_inverse_den))
    add_constraint(var >= new_var);
  else
    add_constraint(var <= new_var);
  // Remove the temporarily added dimension.
  remove_higher_space_dimensions(space_dim);
}

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) {
  // 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");
  // The relation symbol cannot be a disequality.
  if (relsym == NOT_EQUAL)
    throw_generic("generalized_affine_image(v, r, e, d)",
                  "r is the disequality 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);
    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];
  PPL_DIRTY_TEMP_COEFFICIENT(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.
    reset_shortest_path_closed();
    switch (relsym) {
    case LESS_OR_EQUAL:
      // Add the constraint `var <= b/denominator'.
      add_dbm_constraint(0, v, b, denominator);
      break;
    case GREATER_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");
    }
    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.
      PPL_DIRTY_TEMP(N, d);
      switch (relsym) {
      case LESS_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.
          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);
              assign_r(dbm_v[i], PLUS_INFINITY, ROUND_NOT_NEEDED);
            }
          }
          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'.
            assign_r(dbm_v0, PLUS_INFINITY, ROUND_NOT_NEEDED);
            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())
            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.
              reset_shortest_path_closed();
            }
          }
        }
        break;

      case GREATER_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.
          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);
              assign_r(dbm[i][v], PLUS_INFINITY, ROUND_NOT_NEEDED);
            }
          }
          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'.
            assign_r(dbm_0v, PLUS_INFINITY, ROUND_NOT_NEEDED);
            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())
            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.
              reset_shortest_path_closed();
            }
          }
        }
        break;

      default:
        // We already dealt with the other cases.
        throw std::runtime_error("PPL internal error");
      }
      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);
  PPL_DIRTY_TEMP_COEFFICIENT(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;

  PPL_DIRTY_TEMP(N, sum);
  // Index of variable that is unbounded in `this->dbm'.
  PPL_UNINITIALIZED(dimension_type, pinf_index);
  // Number of unbounded variables found.
  dimension_type pinf_count = 0;

  // Speculative allocation of temporaries to be used in the following loops.
  PPL_DIRTY_TEMP(N, coeff_i);
  PPL_DIRTY_TEMP_COEFFICIENT(minus_sc_i);

  switch (relsym) {
  case LESS_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;
      }
      if (sign_i > 0)
        assign_r(coeff_i, sc_i, ROUND_UP);
      else {
        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())
      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.
      PPL_DIRTY_TEMP(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_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;
      }
      if (sign_i > 0)
        assign_r(coeff_i, sc_i, ROUND_UP);
      else {
        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())
      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.
      PPL_DIRTY_TEMP(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");
  }
  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 relation symbol cannot be a disequality.
  if (relsym == NOT_EQUAL)
    throw_generic("generalized_affine_image(e1, r, e2)",
                  "r is the disequality 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_OR_EQUAL:
      refine_no_check(lhs <= rhs);
      break;
    case EQUAL:
      refine_no_check(lhs == rhs);
      break;
    case GREATER_OR_EQUAL:
      refine_no_check(lhs >= rhs);
      break;
    default:
      // We already dealt with the other cases.
      throw std::runtime_error("PPL internal error");
    }
  }
  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_OR_EQUAL)
        new_relsym = GREATER_OR_EQUAL;
      else if (relsym == GREATER_OR_EQUAL)
        new_relsym = LESS_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.
      // Existentially quantify 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_OR_EQUAL:
        refine_no_check(lhs <= rhs);
        break;
      case EQUAL:
        refine_no_check(lhs == rhs);
        break;
      case GREATER_OR_EQUAL:
        refine_no_check(lhs >= rhs);
        break;
      default:
        // We already dealt with the other cases.
        throw std::runtime_error("PPL internal error");
      }
    }
    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 refine_no_check()
      // ensures some approximation is tried even when the constraint
      // is not a bounded difference.
      affine_image(new_var, rhs);
      // Existentially quantify 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 refine_no_check() will simply ignore it.
      // Should we compute approximations for this constraint?
      switch (relsym) {
      case LESS_OR_EQUAL:
        refine_no_check(lhs <= new_var);
        break;
      case EQUAL:
        refine_no_check(lhs == new_var);
        break;
      case GREATER_OR_EQUAL:
        refine_no_check(lhs >= new_var);
        break;
      default:
        // We already dealt with the other cases.
        throw std::runtime_error("PPL internal error");
      }
      // 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) {
  // 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");
  // The relation symbol cannot be a disequality.
  if (relsym == NOT_EQUAL)
    throw_generic("generalized_affine_preimage(v, r, e, d)",
                  "r is the disequality 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);
    return;
  }

  // The preimage 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_OR_EQUAL)
      ? GREATER_OR_EQUAL : LESS_OR_EQUAL;
    const Linear_Expression inverse
      = expr - (expr_v + denominator)*var;
    PPL_DIRTY_TEMP_COEFFICIENT(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;
  }

  refine(var, relsym, expr, denominator);
  // If the shrunk BD_Shape is empty, its preimage is empty too; ...
  if (is_empty())
    return;
  // ...  otherwise, since the relation was not invertible,
  // we just forget all constraints on `v'.
  forget_all_dbm_constraints(v);
  // Shortest-path closure is preserved, but not reduction.
  if (marked_shortest_path_reduced())
    reset_shortest_path_reduced();
  assert(OK());
}

template <typename T>
void
BD_Shape<T>::generalized_affine_preimage(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 bds_space_dim = space_dimension();
  const dimension_type lhs_space_dim = lhs.space_dimension();
  if (bds_space_dim < lhs_space_dim)
    throw_dimension_incompatible("generalized_affine_preimage(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 (bds_space_dim < rhs_space_dim)
    throw_dimension_incompatible("generalized_affine_preimage(e1, r, e2)",
                                 "e2", rhs);

  // Strict relation symbols are not admitted for BDSs.
  if (relsym == LESS_THAN || relsym == GREATER_THAN)
    throw_generic("generalized_affine_preimage(e1, r, e2)",
                  "r is a strict relation symbol and "
                  "*this is a BD_Shape");
  // The relation symbol cannot be a disequality.
  if (relsym == NOT_EQUAL)
    throw_generic("generalized_affine_preimage(e1, r, e2)",
                  "r is the disequality relation symbol and "
                  "*this is a BD_Shape");

  // The preimage 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 this case, preimage and image happen to be the same.
    generalized_affine_image(lhs, relsym, rhs);
    return;
  }
  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 preimages 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_OR_EQUAL)
        new_relsym = GREATER_OR_EQUAL;
      else if (relsym == GREATER_OR_EQUAL)
        new_relsym = LESS_OR_EQUAL;
    }
    Linear_Expression expr = rhs - b_lhs;
    generalized_affine_preimage(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.

      // 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_OR_EQUAL:
        refine_no_check(lhs <= rhs);
        break;
      case EQUAL:
        refine_no_check(lhs == rhs);
        break;
      case GREATER_OR_EQUAL:
        refine_no_check(lhs >= rhs);
        break;
      default:
        // We already dealt with the other cases.
        throw std::runtime_error("PPL internal error");
      }

      // If the shrunk BD_Shape is empty, its preimage is empty too; ...
      if (is_empty())
        return;
      // Existentially quantify all variables in the lhs.
      for (dimension_type i = lhs_vars.size(); i-- > 0; )
        forget_all_dbm_constraints(lhs_vars[i].id() + 1);
    }
    else {

      // Some variables in `lhs' also occur in `rhs'.
      // To ease the computation, we add an additional dimension.
      const Variable new_var = Variable(bds_space_dim);
      add_space_dimensions_and_embed(1);
      // Constrain the new dimension to be equal to `lhs'.
      // NOTE: calling affine_image() instead of refine_no_check()
      // ensures some approximation is tried even when the constraint
      // is not a bounded difference.
      affine_image(new_var, lhs);
      // Existentiallly quantify 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'.
      // Note: if `rhs == a_rhs*v + b_rhs' where `a_rhs' is in {0, 1},
      // then one of the following constraints will be added,
      // since it is a bounded difference. Else the method
      // refine_no_check() will ignore it, because the
      // constraint is NOT a bounded difference.
      switch (relsym) {
      case LESS_OR_EQUAL:
        refine_no_check(new_var <= rhs);
        break;
      case EQUAL:
        refine_no_check(new_var == rhs);
        break;
      case GREATER_OR_EQUAL:
        refine_no_check(new_var >= rhs);
        break;
      default:
        // We already dealt with the other cases.
        throw std::runtime_error("PPL internal error");
      }
      // Remove the temporarily added dimension.
      remove_higher_space_dimensions(bds_space_dim);
    }
  }

  assert(OK());
}

template <typename T>
Constraint_System
BD_Shape<T>::constraints() const {
  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);

    PPL_DIRTY_TEMP_COEFFICIENT(a);
    PPL_DIRTY_TEMP_COEFFICIENT(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];
      if (is_additive_inverse(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];
        if (is_additive_inverse(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 {
  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);

    PPL_DIRTY_TEMP_COEFFICIENT(num);
    PPL_DIRTY_TEMP_COEFFICIENT(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 Bit_Row& 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 Bit_Row& 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;
}

template <typename T>
void
BD_Shape<T>::expand_space_dimension(Variable var, dimension_type m) {
  dimension_type old_dim = space_dimension();
  // `var' should be one of the dimensions of the vector space.
  if (var.space_dimension() > old_dim)
    throw_dimension_incompatible("expand_space_dimension(v, m)", "v", var);

  // The space dimension of the resulting BDS should not
  // overflow the maximum allowed space dimension.
  if (m > max_space_dimension() - space_dimension())
    throw_generic("expand_dimension(v, m)",
                  "adding m new space dimensions exceeds "
                  "the maximum allowed space dimension");

  // Nothing to do, if no dimensions must be added.
  if (m == 0)
    return;

  // Add the required new dimensions.
  add_space_dimensions_and_embed(m);

  // For each constraints involving variable `var', we add a
  // similar constraint with the new variable substituted for
  // variable `var'.
  const dimension_type v_id = var.id() + 1;
  const DB_Row<N>& dbm_v = dbm[v_id];
  for (dimension_type i = old_dim + 1; i-- > 0; ) {
    DB_Row<N>& dbm_i = dbm[i];
    const N& dbm_i_v = dbm[i][v_id];
    const N& dbm_v_i = dbm_v[i];
    for (dimension_type j = old_dim+1; j < old_dim+m+1; ++j) {
      dbm_i[j] = dbm_i_v;
      dbm[j][i] = dbm_v_i;
    }
  }
  // In general, adding a constraint does not preserve the shortest-path
  // closure or reduction of the bounded difference shape.
  if (marked_shortest_path_closed())
    reset_shortest_path_closed();
  assert(OK());
}

template <typename T>
void
BD_Shape<T>::fold_space_dimensions(const Variables_Set& to_be_folded,
                                   Variable var) {
  const dimension_type space_dim = space_dimension();
  // `var' should be one of the dimensions of the BDS.
  if (var.space_dimension() > space_dim)
    throw_dimension_incompatible("fold_space_dimensions(tbf, v)",
                                 "v", var);

  // The folding of no dimensions is a no-op.
  if (to_be_folded.empty())
    return;

  // All variables in `to_be_folded' should be dimensions of the BDS.
  if (to_be_folded.space_dimension() > space_dim)
    throw_dimension_incompatible("fold_space_dimensions(tbf, ...)",
                                 to_be_folded.space_dimension());

  // Moreover, `var.id()' should not occur in `to_be_folded'.
  if (to_be_folded.find(var.id()) != to_be_folded.end())
    throw_generic("fold_space_dimensions(tbf, v)",
                  "v should not occur in tbf");

  shortest_path_closure_assign();
  if (!marked_empty()) {
    // Recompute the elements of the row and the column corresponding
    // to variable `var' by taking the join of their value with the
    // value of the corresponding elements in the row and column of the
    // variable `to_be_folded'.
    const dimension_type v_id = var.id() + 1;
    DB_Row<N>& dbm_v = dbm[v_id];
    for (Variables_Set::const_iterator i = to_be_folded.begin(),
           tbf_end = to_be_folded.end(); i != tbf_end; ++i) {
      const dimension_type tbf_id = *i + 1;
      const DB_Row<N>& dbm_tbf = dbm[tbf_id];
      for (dimension_type j = space_dim + 1; j-- > 0; ) {
        max_assign(dbm[j][v_id], dbm[j][tbf_id]);
        max_assign(dbm_v[j], dbm_tbf[j]);
      }
    }
  }
  remove_space_dimensions(to_be_folded);
}

/*! \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 bounded difference shape.
    dimension_type n = c.space_dimension();
    if (c.marked_empty())
      s << "false";
    else {
      PPL_DIRTY_TEMP(N, v);
      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];
          if (is_additive_inverse(c_j_i, 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 (sgn(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);
                neg_assign_r(v, c_j_i, ROUND_DOWN);
                s << " >= " << v;
              }
              else {
                // We have got a constraint with two Variables.
                if (sgn(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);
                  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 (sgn(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);
                  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);
  s << "\n";
  redundancy_dbm.ascii_dump(s);
}

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;
  if (!redundancy_dbm.ascii_load(s))
    return false;
  return true;
}

template <typename T>
memory_size_type
BD_Shape<T>::external_memory_in_bytes() const {
  return dbm.external_memory_in_bytes()
    + redundancy_dbm.external_memory_in_bytes();
}

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 << "][" << j << "] = "
                  << dbm[i][j] << "!"
                  << 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.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;
    }
  }

  // The following tests might result in false alarms when using floating
  // point coefficients: they are only meaningful if the coefficient type
  // base is exact (since otherwise shortest-path closure is approximated).
  if (std::numeric_limits<coefficient_type_base>::is_exact) {

    // 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 << "][" << j << "] = "
                      << dbm[i][j] << " is marked as non-redundant!"
                      << std::endl;
#endif
            return false;
          }

      BD_Shape x = *this;
      x.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::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::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::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 Congruence& cg) const {
  std::ostringstream s;
  s << "PPL::BD_Shape::" << method << ":" << std::endl
    << "this->space_dimension() == " << space_dimension()
    << ", cg->space_dimension == " << cg.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::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_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::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::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 2146. */

/* Automatically generated from PPL source file ../src/Box.templates.hh line 39. */
#include <iostream>

namespace Parma_Polyhedra_Library {

template <typename ITV>
inline
Box<ITV>::Box(dimension_type num_dimensions, Degenerate_Element kind)
  : seq(num_dimensions <= max_space_dimension()
	? num_dimensions
	: (throw_space_dimension_overflow("Box(n, k)",
					  "n exceeds the maximum "
					  "allowed space dimension"),
	   num_dimensions)),
    status() {
  // In a box that is marked empty the intervals are completely
  // meaningless: we exploit this by avoiding their initialization.
  if (kind == UNIVERSE) {
    for (dimension_type i = num_dimensions; i-- > 0; )
      seq[i].assign(UNIVERSE);
    set_empty_up_to_date();
  }
  else
    set_empty();
  assert(OK());
}

template <typename ITV>
inline
Box<ITV>::Box(const Constraint_System& cs)
  : seq(cs.space_dimension() <= max_space_dimension()
	? cs.space_dimension()
	: (throw_space_dimension_overflow("Box(cs)",
					  "cs exceeds the maximum "
					  "allowed space dimension"),
	   cs.space_dimension())),
    status() {
  // FIXME: check whether we can avoid the double initialization.
  for (dimension_type i = cs.space_dimension(); i-- > 0; )
    seq[i].assign(UNIVERSE);
  add_constraints_no_check(cs);
}

template <typename ITV>
inline
Box<ITV>::Box(const Congruence_System& cgs)
  : seq(cgs.space_dimension() <= max_space_dimension()
	? cgs.space_dimension()
	: (throw_space_dimension_overflow("Box(cgs)",
					  "cgs exceeds the maximum "
					  "allowed space dimension"),
	   cgs.space_dimension())),
    status() {
  // FIXME: check whether we can avoid the double initialization.
  for (dimension_type i = cgs.space_dimension(); i-- > 0; )
    seq[i].assign(UNIVERSE);
  add_congruences_no_check(cgs);
}

template <typename ITV>
template <typename Other_ITV>
inline
Box<ITV>::Box(const Box<Other_ITV>& y, Complexity_Class)
  : seq(y.space_dimension()),
    // FIXME: why the following does not work?
    // status(y.status) {
    status() {
  // FIXME: remove when the above is fixed.
  if (y.marked_empty())
    set_empty();

  if (!y.marked_empty())
    for (dimension_type k = y.space_dimension(); k-- > 0; )
      seq[k].assign(y.seq[k]);
  assert(OK());
}

template <typename ITV>
Box<ITV>::Box(const Generator_System& gs)
  : seq(gs.space_dimension() <= max_space_dimension()
	? gs.space_dimension()
	: (throw_space_dimension_overflow("Box(gs)",
					  "gs exceeds the maximum "
					  "allowed space dimension"),
	   gs.space_dimension())),
    status() {
  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 box.
    set_empty();
    return;
  }

  // The empty flag will be meaningful, whatever happens from now on.
  set_empty_up_to_date();

  const dimension_type space_dim = space_dimension();
  PPL_DIRTY_TEMP0(mpq_class, q);
  bool point_seen = false;
  // Going through all the points.
  for (Generator_System::const_iterator
	 gs_i = gs_begin; gs_i != gs_end; ++gs_i) {
    const Generator& g = *gs_i;
    if (g.is_point()) {
      const Coefficient& d = g.divisor();
      if (point_seen) {
	// This is not the first point: `seq' already contains valid values.
	for (dimension_type i = space_dim; i-- > 0; ) {
	  assign_r(q.get_num(), g.coefficient(Variable(i)), ROUND_NOT_NEEDED);
	  assign_r(q.get_den(), d, ROUND_NOT_NEEDED);
	  q.canonicalize();
	  seq[i].join_assign(q);
	}
      }
      else {
	// This is the first point seen: initialize `seq'.
	point_seen = true;
	for (dimension_type i = space_dim; i-- > 0; ) {
	  assign_r(q.get_num(), g.coefficient(Variable(i)), ROUND_NOT_NEEDED);
	  assign_r(q.get_den(), d, ROUND_NOT_NEEDED);
	  q.canonicalize();
	  seq[i].assign(q);
	}
      }
    }
  }

  if (!point_seen)
    // The generator system is not empty, but contains no points.
    throw std::invalid_argument("PPL::Box<ITV>::Box(gs):\n"
				"the non-empty generator system gs "
				"contains no points.");

  // Going through all the lines, rays and closure points.
  ITV q_interval;
  for (Generator_System::const_iterator gs_i = gs_begin;
       gs_i != gs_end; ++gs_i) {
    const Generator& g = *gs_i;
    switch (g.type()) {
    case Generator::LINE:
      for (dimension_type i = space_dim; i-- > 0; )
	if (g.coefficient(Variable(i)) != 0)
	  seq[i].assign(UNIVERSE);
      break;
    case Generator::RAY:
      for (dimension_type i = space_dim; i-- > 0; )
	switch (sgn(g.coefficient(Variable(i)))) {
	case 1:
	  seq[i].upper_set(UNBOUNDED);
	  break;
	case -1:
	  seq[i].lower_set(UNBOUNDED);
	  break;
	default:
	  break;
	}
      break;
    case Generator::CLOSURE_POINT:
      {
	const Coefficient& d = g.divisor();
	for (dimension_type i = space_dim; i-- > 0; ) {
	  assign_r(q.get_num(), g.coefficient(Variable(i)), ROUND_NOT_NEEDED);
	  assign_r(q.get_den(), d, ROUND_NOT_NEEDED);
	  q.canonicalize();
	  ITV& seq_i = seq[i];
	  seq_i.lower_widen(q, true);
	  seq_i.upper_widen(q, true);
	}
      }
      break;
    default:
      // Points already dealt with.
      break;
    }
  }
  assert(OK());
}

template <typename ITV>
template <typename T>
Box<ITV>::Box(const BD_Shape<T>& bds, Complexity_Class)
  : seq(bds.space_dimension() <= max_space_dimension()
	? bds.space_dimension()
	: (throw_space_dimension_overflow("Box(bds)",
					  "bds exceeds the maximum "
					  "allowed space dimension"),
	   bds.space_dimension())),
    status() {
  // Expose all the interval constraints.
  bds.shortest_path_closure_assign();
  if (bds.marked_empty()) {
    set_empty();
    assert(OK());
    return;
  }

  // The empty flag will be meaningful, whatever happens from now on.
  set_empty_up_to_date();

  const dimension_type space_dim = space_dimension();
  if (space_dim == 0) {
    assert(OK());
    return;
  }

  PPL_DIRTY_TEMP(typename BD_Shape<T>::coefficient_type, tmp);
  const DB_Row<typename BD_Shape<T>::coefficient_type>& dbm_0 = bds.dbm[0];
  for (dimension_type i = space_dim; i-- > 0; ) {
    ITV& seq_i = seq[i];
    // Set the upper bound.
    const typename BD_Shape<T>::coefficient_type& u = dbm_0[i+1];
    if (is_plus_infinity(u))
      seq_i.upper_set_uninit(UNBOUNDED);
    else
      seq_i.upper_set_uninit(u);

    // Set the lower bound.
    const typename BD_Shape<T>::coefficient_type& negated_l = bds.dbm[i+1][0];
    if (is_plus_infinity(negated_l))
      seq_i.lower_set_uninit(UNBOUNDED);
    else {
      neg_assign_r(tmp, negated_l, ROUND_DOWN);
      seq_i.lower_set_uninit(tmp);
    }

    // Complete the interval initialization.
    seq_i.complete_init();
  }
  assert(OK());
}

template <typename ITV>
template <typename T>
Box<ITV>::Box(const Octagonal_Shape<T>& oct, Complexity_Class)
  : seq(oct.space_dimension() <= max_space_dimension()
	? oct.space_dimension()
	: (throw_space_dimension_overflow("Box(oct)",
					  "oct exceeds the maximum "
					  "allowed space dimension"),
	   oct.space_dimension())),
    status() {
  // Expose all the interval constraints.
  oct.strong_closure_assign();
  if (oct.marked_empty()) {
    set_empty();
    return;
  }

  // The empty flag will be meaningful, whatever happens from now on.
  set_empty_up_to_date();

  const dimension_type space_dim = space_dimension();
  if (space_dim == 0)
    return;

  PPL_DIRTY_TEMP0(mpq_class, bound);
  for (dimension_type i = space_dim; i-- > 0; ) {
    ITV& seq_i = seq[i];
    const dimension_type ii = 2*i;
    const dimension_type cii = ii + 1;

    // Set the upper bound.
    const typename Octagonal_Shape<T>::coefficient_type& twice_ub
      = oct.matrix[cii][ii];
    if (!is_plus_infinity(twice_ub)) {
      assign_r(bound, twice_ub, ROUND_NOT_NEEDED);
      div2exp_assign_r(bound, bound, 1, ROUND_NOT_NEEDED);
      seq_i.upper_set_uninit(bound);
    }
    else
      seq_i.upper_set_uninit(UNBOUNDED);

    // Set the lower bound.
    const typename Octagonal_Shape<T>::coefficient_type& twice_lb
      = oct.matrix[ii][cii];
    if (!is_plus_infinity(twice_lb)) {
      assign_r(bound, twice_lb, ROUND_NOT_NEEDED);
      neg_assign_r(bound, bound, ROUND_NOT_NEEDED);
      div2exp_assign_r(bound, bound, 1, ROUND_NOT_NEEDED);
      seq_i.lower_set_uninit(bound);
    }
    else
      seq_i.lower_set_uninit(UNBOUNDED);
    seq_i.complete_init();
  }
}

template <typename ITV>
Box<ITV>::Box(const Polyhedron& ph, Complexity_Class complexity)
  : seq(ph.space_dimension() <= max_space_dimension()
	? ph.space_dimension()
	: (throw_space_dimension_overflow("Box(ph)",
					  "ph exceeds the maximum "
					  "allowed space dimension"),
	   ph.space_dimension())),
    status() {
  // The empty flag will be meaningful, whatever happens from now on.
  set_empty_up_to_date();

  // We do not need to bother about `complexity' if:
  // a) the polyhedron is already marked empty; or ...
  if (ph.marked_empty()) {
    set_empty();
    return;
  }

  // b) the polyhedron is zero-dimensional; or ...
  const dimension_type space_dim = ph.space_dimension();
  if (space_dim == 0)
    return;

  // c) the polyhedron is already described by a generator system.
  if (ph.generators_are_up_to_date() && !ph.has_pending_constraints()) {
    Box tmp(ph.generators());
    swap(tmp);
    return;
  }

  // Here generators are not up-to-date or there are pending constraints.
  assert(ph.constraints_are_up_to_date());

  if (complexity == POLYNOMIAL_COMPLEXITY) {
    // FIXME: is there a way to avoid this initialization?
    for (dimension_type i = space_dimension(); i-- > 0; )
      seq[i].assign(UNIVERSE);
    // Extract easy-to-find bounds from constraints.
    refine_with_constraints(ph.simplified_constraints());
  }
  else if (complexity == SIMPLEX_COMPLEXITY) {
    MIP_Problem lp(space_dim);
    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(),
	     ph_cs_end = ph_cs.end(); i != ph_cs_end; ++i) {
	const Constraint& c = *i;
	if (c.is_strict_inequality())
	  lp.add_constraint(Linear_Expression(c) >= 0);
	else
	  lp.add_constraint(c);
      }
    // Check for unsatisfiability.
    if (!lp.is_satisfiable()) {
      set_empty();
      return;
    }
    // Get all the bounds for the space dimensions.
    Generator g(point());
    PPL_DIRTY_TEMP0(mpq_class, bound);
    PPL_DIRTY_TEMP(Coefficient, bound_num);
    PPL_DIRTY_TEMP(Coefficient, bound_den);
    for (dimension_type i = space_dim; i-- > 0; ) {
      ITV& seq_i = seq[i];
      lp.set_objective_function(Variable(i));
      // Evaluate upper bound.
      lp.set_optimization_mode(MAXIMIZATION);
      if (lp.solve() == OPTIMIZED_MIP_PROBLEM) {
	g = lp.optimizing_point();
	lp.evaluate_objective_function(g, bound_num, bound_den);
	assign_r(bound.get_num(), bound_num, ROUND_NOT_NEEDED);
	assign_r(bound.get_den(), bound_den, ROUND_NOT_NEEDED);
	assert(is_canonical(bound));
	seq_i.upper_set_uninit(bound);
      }
      else
	seq_i.upper_set_uninit(UNBOUNDED);
      // Evaluate optimal lower bound.
      lp.set_optimization_mode(MINIMIZATION);
      if (lp.solve() == OPTIMIZED_MIP_PROBLEM) {
	g = lp.optimizing_point();
	lp.evaluate_objective_function(g, bound_num, bound_den);
	assign_r(bound.get_num(), bound_num, ROUND_NOT_NEEDED);
	assign_r(bound.get_den(), bound_den, ROUND_NOT_NEEDED);
	assert(is_canonical(bound));
	seq_i.lower_set_uninit(bound);
      }
      else
	seq_i.lower_set_uninit(UNBOUNDED);
      seq_i.complete_init();
    }
  }
  else {
    assert(complexity == ANY_COMPLEXITY);
    if (ph.is_empty())
      set_empty();
    else {
      Box tmp(ph.generators());
      swap(tmp);
    }
  }
}

template <typename ITV>
Box<ITV>::Box(const Grid& gr, Complexity_Class)
  : seq(gr.space_dimension() <= max_space_dimension()
	? gr.space_dimension()
	: (throw_space_dimension_overflow("Box(gr)",
					  "gr exceeds the maximum "
					  "allowed space dimension"),
	   gr.space_dimension())),
    status() {

  // FIXME: here we are not taking advantage of intervals with restrictions!

  if (gr.marked_empty()) {
    set_empty();
    return;
  }

  // The empty flag will be meaningful, whatever happens from now on.
  set_empty_up_to_date();

  const dimension_type space_dim = gr.space_dimension();

  if (space_dim == 0)
    return;

  if (!gr.generators_are_up_to_date() && !gr.update_generators()) {
    // Updating found the grid empty.
    set_empty();
    return;
  }

  assert(!gr.gen_sys.empty());

  // For each dimension that is bounded by the grid, set both bounds
  // of the interval to the value of the associated coefficient in a
  // generator point.
  PPL_DIRTY_TEMP0(mpq_class, bound);
  PPL_DIRTY_TEMP(Coefficient, bound_num);
  PPL_DIRTY_TEMP(Coefficient, bound_den);
  for (dimension_type i = space_dim; i-- > 0; ) {
    ITV& seq_i = seq[i];
    Variable var(i);
    bool max;
    if (gr.maximize(var, bound_num, bound_den, max)) {
      assign_r(bound.get_num(), bound_num, ROUND_NOT_NEEDED);
      assign_r(bound.get_den(), bound_den, ROUND_NOT_NEEDED);
      bound.canonicalize();
      seq_i.assign(bound);
    }
    else
      seq_i.assign(UNIVERSE);
  }
}

template <typename ITV>
template <typename D1, typename D2, typename R>
Box<ITV>::Box(const Partially_Reduced_Product<D1, D2, R>& dp,
              Complexity_Class complexity)
  : seq(), status() {
  if (dp.space_dimension() > max_space_dimension())
    throw_space_dimension_overflow("Box(dp)",
                                   "dp exceeds the maximum "
                                   "allowed space dimension");
  Box tmp1(dp.domain1(), complexity);
  Box tmp2(dp.domain2(), complexity);
  tmp1.intersection_assign(tmp2);
  swap(tmp1);
}

template <typename ITV>
inline void
Box<ITV>::add_space_dimensions_and_embed(const dimension_type m) {
  // Adding no dimensions is a no-op.
  if (m == 0)
    return;
  // To embed an n-dimension space box in a (n+m)-dimension space,
  // we just add `m' new universe elements to the sequence.
  seq.insert(seq.end(), m, ITV(UNIVERSE));
  assert(OK());
}

template <typename ITV>
inline void
Box<ITV>::add_space_dimensions_and_project(const dimension_type m) {
  // Adding no dimensions is a no-op.
  if (m == 0)
    return;
  // Add `m' new zero elements to the sequence.
  seq.insert(seq.end(), m, ITV(0));
  assert(OK());
}

template <typename ITV>
bool
operator==(const Box<ITV>& x, const Box<ITV>& y) {
  const dimension_type x_space_dim = x.space_dimension();
  if (x_space_dim != y.space_dimension())
    return false;

  if (x.is_empty())
    return y.is_empty();

  if (y.is_empty())
    return x.is_empty();

  for (dimension_type k = x_space_dim; k-- > 0; )
    if (x.seq[k] != y.seq[k])
      return false;
  return true;
}

template <typename ITV>
bool
Box<ITV>::bounds(const Linear_Expression& expr, const bool from_above) const {
  // `expr' should be dimension-compatible with `*this'.
  const dimension_type expr_space_dim = expr.space_dimension();
  const dimension_type space_dim = space_dimension();
  if (space_dim < expr_space_dim)
    throw_dimension_incompatible((from_above
				  ? "bounds_from_above(e)"
				  : "bounds_from_below(e)"), "e", expr);
  // A zero-dimensional or empty Box bounds everything.
  if (space_dim == 0 || is_empty())
    return true;

  const int from_above_sign = from_above ? 1 : -1;
  for (dimension_type i = expr_space_dim; i-- > 0; )
    switch (sgn(expr.coefficient(Variable(i))) * from_above_sign) {
    case 1:
      if (seq[i].upper_is_unbounded())
	return false;
      break;
    case 0:
      // Nothing to do.
      break;
    case -1:
      if (seq[i].lower_is_unbounded())
	return false;
      break;
    }
  return true;
}

template <typename ITV>
Poly_Con_Relation
interval_relation(const ITV& i,
		  const Constraint::Type constraint_type,
		  Coefficient_traits::const_reference num,
		  Coefficient_traits::const_reference den) {

  if (i.is_universe())
    return Poly_Con_Relation::strictly_intersects();

  PPL_DIRTY_TEMP0(mpq_class, bound);
  assign_r(bound.get_num(), num, ROUND_NOT_NEEDED);
  assign_r(bound.get_den(), den, ROUND_NOT_NEEDED);
  bound.canonicalize();
  neg_assign_r(bound, bound, ROUND_NOT_NEEDED);
  const bool is_lower_bound = (den > 0);

  PPL_DIRTY_TEMP0(mpq_class, bound_diff);
  if (constraint_type == Constraint::EQUALITY) {
    if (i.lower_is_unbounded()) {
      assert(!i.upper_is_unbounded());
      assign_r(bound_diff, i.upper(), ROUND_NOT_NEEDED);
      sub_assign_r(bound_diff, bound_diff, bound, ROUND_NOT_NEEDED);
      switch (sgn(bound_diff)) {
      case 1:
	return Poly_Con_Relation::strictly_intersects();
      case 0:
	return i.upper_is_open()
	  ? Poly_Con_Relation::is_disjoint()
	  : Poly_Con_Relation::strictly_intersects();
      case -1:
	return Poly_Con_Relation::is_disjoint();
      }
    }
    else {
      assign_r(bound_diff, i.lower(), ROUND_NOT_NEEDED);
      sub_assign_r(bound_diff, bound_diff, bound, ROUND_NOT_NEEDED);
      switch (sgn(bound_diff)) {
      case 1:
	return Poly_Con_Relation::is_disjoint();
      case 0:
	if (i.lower_is_open())
	  return Poly_Con_Relation::is_disjoint();
        if (i.is_singleton())
          return Poly_Con_Relation::is_included()
            && Poly_Con_Relation::saturates();
        return Poly_Con_Relation::strictly_intersects();
      case -1:
	if (i.upper_is_unbounded())
	  return Poly_Con_Relation::strictly_intersects();
	else {
	  assign_r(bound_diff, i.upper(), ROUND_NOT_NEEDED);
	  sub_assign_r(bound_diff, bound_diff, bound, ROUND_NOT_NEEDED);
	  switch (sgn(bound_diff)) {
	  case 1:
	    return Poly_Con_Relation::strictly_intersects();
	  case 0:
	    if (i.upper_is_open())
	      return Poly_Con_Relation::is_disjoint();
	    else
	      return Poly_Con_Relation::strictly_intersects();
	  case -1:
	    return Poly_Con_Relation::is_disjoint();
	  }
	}
      }
    }
  }

  assert(constraint_type != Constraint::EQUALITY);
  if (is_lower_bound) {
    if (i.lower_is_unbounded()) {
      assert(!i.upper_is_unbounded());
      assign_r(bound_diff, i.upper(), ROUND_NOT_NEEDED);
      sub_assign_r(bound_diff, bound_diff, bound, ROUND_NOT_NEEDED);
      switch (sgn(bound_diff)) {
      case 1:
	return Poly_Con_Relation::strictly_intersects();
      case 0:
	if (constraint_type == Constraint::STRICT_INEQUALITY
	    || i.upper_is_open())
	  return Poly_Con_Relation::is_disjoint();
	else
	  return Poly_Con_Relation::strictly_intersects();
      case -1:
	return Poly_Con_Relation::is_disjoint();
      }
    }
    else {
      assign_r(bound_diff, i.lower(), ROUND_NOT_NEEDED);
      sub_assign_r(bound_diff, bound_diff, bound, ROUND_NOT_NEEDED);
      switch (sgn(bound_diff)) {
      case 1:
	return Poly_Con_Relation::is_included();
      case 0:
	if (constraint_type == Constraint::NONSTRICT_INEQUALITY
	    || i.lower_is_open()) {
	  Poly_Con_Relation result = Poly_Con_Relation::is_included();
	  if (i.is_singleton())
	    result = result && Poly_Con_Relation::saturates();
	  return result;
	}
	else {
	  assert(constraint_type == Constraint::STRICT_INEQUALITY
		 && !i.lower_is_open());
	  if (i.is_singleton())
	    return Poly_Con_Relation::is_disjoint()
	      && Poly_Con_Relation::saturates();
	  else
	    return Poly_Con_Relation::strictly_intersects();
	}
      case -1:
	if (i.upper_is_unbounded())
	  return Poly_Con_Relation::strictly_intersects();
	else {
	  assign_r(bound_diff, i.upper(), ROUND_NOT_NEEDED);
	  sub_assign_r(bound_diff, bound_diff, bound, ROUND_NOT_NEEDED);
	  switch (sgn(bound_diff)) {
	  case 1:
	    return Poly_Con_Relation::strictly_intersects();
	  case 0:
	    if (constraint_type == Constraint::STRICT_INEQUALITY
		|| i.upper_is_open())
	      return Poly_Con_Relation::is_disjoint();
	    else
	      return Poly_Con_Relation::strictly_intersects();
	  case -1:
	    return Poly_Con_Relation::is_disjoint();
	  }
	}
      }
    }
  }
  else {
    // `c' is an upper bound.
    if (i.upper_is_unbounded())
      return Poly_Con_Relation::strictly_intersects();
    else {
      assign_r(bound_diff, i.upper(), ROUND_NOT_NEEDED);
      sub_assign_r(bound_diff, bound_diff, bound, ROUND_NOT_NEEDED);
      switch (sgn(bound_diff)) {
      case -1:
	return Poly_Con_Relation::is_included();
      case 0:
	if (constraint_type == Constraint::NONSTRICT_INEQUALITY
	    || i.upper_is_open()) {
	  Poly_Con_Relation result = Poly_Con_Relation::is_included();
	  if (i.is_singleton())
	    result = result && Poly_Con_Relation::saturates();
	  return result;
	}
	else {
	  assert(constraint_type == Constraint::STRICT_INEQUALITY
		 && !i.upper_is_open());
	  if (i.is_singleton())
	    return Poly_Con_Relation::is_disjoint()
	      && Poly_Con_Relation::saturates();
	  else
	    return Poly_Con_Relation::strictly_intersects();
	}
      case 1:
	if (i.lower_is_unbounded())
	  return Poly_Con_Relation::strictly_intersects();
	else {
	  assign_r(bound_diff, i.lower(), ROUND_NOT_NEEDED);
	  sub_assign_r(bound_diff, bound_diff, bound, ROUND_NOT_NEEDED);
	  switch (sgn(bound_diff)) {
	  case -1:
	    return Poly_Con_Relation::strictly_intersects();
	  case 0:
	    if (constraint_type == Constraint::STRICT_INEQUALITY
		|| i.lower_is_open())
	      return Poly_Con_Relation::is_disjoint();
	    else
	      return Poly_Con_Relation::strictly_intersects();
	  case 1:
	    return Poly_Con_Relation::is_disjoint();
	  }
	}
      }
    }
  }

  // Quiet a compiler warning: this program point is unreachable.
  throw std::runtime_error("PPL internal error");
}

template <typename ITV>
Poly_Con_Relation
Box<ITV>::relation_with(const Congruence& cg) const {
  const dimension_type cg_space_dim = cg.space_dimension();
  const dimension_type space_dim = space_dimension();

  // Dimension-compatibility check.
  if (cg_space_dim > space_dim)
    throw_dimension_incompatible("relation_with(cg)", cg);

  if (is_empty())
    return Poly_Con_Relation::saturates()
      && Poly_Con_Relation::is_included()
      && Poly_Con_Relation::is_disjoint();

   if (space_dim == 0) {
    if (cg.is_inconsistent())
      return Poly_Con_Relation::is_disjoint();
    else
      return Poly_Con_Relation::saturates()
	&& Poly_Con_Relation::is_included();
  }

  if (cg.is_equality()) {
    const Constraint c(cg);
    return relation_with(c);
  }

  PPL_DIRTY_TEMP0(Rational_Interval, r);
  PPL_DIRTY_TEMP0(Rational_Interval, t);
  PPL_DIRTY_TEMP0(mpq_class, m);
  r = 0;
  for (dimension_type i = cg.space_dimension(); i-- > 0; ) {
    const Coefficient& cg_i = cg.coefficient(Variable(i));
    if (sgn(cg_i) != 0) {
      assign_r(m, cg_i, ROUND_NOT_NEEDED);
      // FIXME: an add_mul_assign() method would come handy here.
      t = seq[i];
      t *= m;
      r += t;
    }
  }

  if (r.lower_is_unbounded() || r.upper_is_unbounded())
    return Poly_Con_Relation::strictly_intersects();


  // Find the value that satisfies the congruence and is
  // nearest to the lower bound such that the point lies on or above it.

  PPL_DIRTY_TEMP_COEFFICIENT(lower);
  PPL_DIRTY_TEMP_COEFFICIENT(mod);
  PPL_DIRTY_TEMP_COEFFICIENT(v);
  mod = cg.modulus();
  v = cg.inhomogeneous_term() % mod;
  assign_r(lower, r.lower(), ROUND_DOWN);
  v -= ((lower / mod) * mod);
  if (v + lower > 0)
    v -= mod;
  return interval_relation(r, Constraint::EQUALITY, v);
}

template <typename ITV>
Poly_Con_Relation
Box<ITV>::relation_with(const Constraint& c) const {
  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);

  if (is_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 c_num_vars = 0;
  dimension_type c_only_var = 0;

  if (extract_interval_constraint(c, c_space_dim, c_num_vars, c_only_var))
    if (c_num_vars == 0)
      // c is 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();
      }
    else {
      // c is an interval constraint.
      return interval_relation(seq[c_only_var],
			       c.type(),
			       c.inhomogeneous_term(),
			       c.coefficient(Variable(c_only_var)));
    }
  else {
    // Deal with a non-trivial and non-interval constraint.
    PPL_DIRTY_TEMP0(Rational_Interval, r);
    PPL_DIRTY_TEMP0(Rational_Interval, t);
    PPL_DIRTY_TEMP0(mpq_class, m);
    r = 0;
    for (dimension_type i = c.space_dimension(); i-- > 0; ) {
      const Coefficient& c_i = c.coefficient(Variable(i));
      if (sgn(c_i) != 0) {
        assign_r(m, c_i, ROUND_NOT_NEEDED);
	// FIXME: an add_mul_assign() method would come handy here.
	t = seq[i];
	t *= m;
	r += t;
      }
    }
    return interval_relation(r,
			     c.type(),
			     c.inhomogeneous_term());
  }

  // Quiet a compiler warning: this program point is unreachable.
  throw std::runtime_error("PPL internal error");
}

template <typename ITV>
Poly_Gen_Relation
Box<ITV>::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 box cannot subsume a generator.
  if (is_empty())
    return Poly_Gen_Relation::nothing();

  // A universe box in a zero-dimensional space subsumes
  // all the generators of a zero-dimensional space.
  if (space_dim == 0)
    return Poly_Gen_Relation::subsumes();

  if (g.is_line_or_ray()) {
    if (g.is_line()) {
      for (dimension_type i = g_space_dim; i-- > 0; )
	if (g.coefficient(Variable(i)) != 0 && !seq[i].is_universe())
	  return Poly_Gen_Relation::nothing();
      return Poly_Gen_Relation::subsumes();
    }
    else {
      assert(g.is_ray());
      for (dimension_type i = g_space_dim; i-- > 0; )
	switch (sgn(g.coefficient(Variable(i)))) {
	case 1:
	  if (!seq[i].upper_is_unbounded())
	    return Poly_Gen_Relation::nothing();
	  break;
	case 0:
	  break;
	case -1:
	  if (!seq[i].lower_is_unbounded())
	    return Poly_Gen_Relation::nothing();
	  break;
	}
      return Poly_Gen_Relation::subsumes();
    }
  }

  // Here `g' is a point or closure point.
  const Coefficient& g_divisor = g.divisor();
  PPL_DIRTY_TEMP0(mpq_class, g_coord);
  PPL_DIRTY_TEMP0(mpq_class, bound);
  for (dimension_type i = g_space_dim; i-- > 0; ) {
    const ITV& seq_i = seq[i];
    if (seq_i.is_universe())
      continue;
    assign_r(g_coord.get_num(), g.coefficient(Variable(i)), ROUND_NOT_NEEDED);
    assign_r(g_coord.get_den(), g_divisor, ROUND_NOT_NEEDED);
    g_coord.canonicalize();
    // Check lower bound.
    if (!seq_i.lower_is_unbounded()) {
      assign_r(bound, seq_i.lower(), ROUND_NOT_NEEDED);
      if (g_coord <= bound) {
	if (seq_i.lower_is_open()) {
	  if (g.is_point() || g_coord != bound)
	    return Poly_Gen_Relation::nothing();
	}
	else if (g_coord != bound)
	  return Poly_Gen_Relation::nothing();
      }
    }
    // Check upper bound.
    if (!seq_i.upper_is_unbounded()) {
      assign_r(bound, seq_i.upper(), ROUND_NOT_NEEDED);
      if (g_coord >= bound) {
	if (seq_i.upper_is_open()) {
	  if (g.is_point() || g_coord != bound)
	    return Poly_Gen_Relation::nothing();
	}
	else if (g_coord != bound)
	  return Poly_Gen_Relation::nothing();
      }
    }
  }
  return Poly_Gen_Relation::subsumes();
}


template <typename ITV>
bool
Box<ITV>::max_min(const Linear_Expression& expr,
                  const bool maximize,
                  Coefficient& ext_n, Coefficient& ext_d,
                  bool& included) const {
  // `expr' should be dimension-compatible with `*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((maximize
				  ? "maximize(e, ...)"
				  : "minimize(e, ...)"), "e", expr);
  // Deal with zero-dim Box first.
  if (space_dim == 0) {
    if (marked_empty())
      return false;
    else {
      ext_n = expr.inhomogeneous_term();
      ext_d = 1;
      included = true;
      return true;
    }
  }

  // For an empty Box we simply return false.
  if (is_empty())
    return false;

  PPL_DIRTY_TEMP0(mpq_class, result);
  assign_r(result, expr.inhomogeneous_term(), ROUND_NOT_NEEDED);
  bool is_included = true;
  const int maximize_sign = maximize ? 1 : -1;
  PPL_DIRTY_TEMP0(mpq_class, bound_i);
  PPL_DIRTY_TEMP0(mpq_class, expr_i);
  for (dimension_type i = expr_space_dim; i-- > 0; ) {
    const ITV& seq_i = seq[i];
    assign_r(expr_i, expr.coefficient(Variable(i)), ROUND_NOT_NEEDED);
    switch (sgn(expr_i) * maximize_sign) {
    case 1:
      if (seq_i.upper_is_unbounded())
	return false;
      assign_r(bound_i, seq_i.upper(), ROUND_NOT_NEEDED);
      add_mul_assign_r(result, bound_i, expr_i, ROUND_NOT_NEEDED);
      if (seq_i.upper_is_open())
	is_included = false;
      break;
    case 0:
      // Nothing to do.
      break;
    case -1:
      if (seq_i.lower_is_unbounded())
	return false;
      assign_r(bound_i, seq_i.lower(), ROUND_NOT_NEEDED);
      add_mul_assign_r(result, bound_i, expr_i, ROUND_NOT_NEEDED);
      if (seq_i.lower_is_open())
	is_included = false;
      break;
    }
  }
  // Extract output info.
  assert(is_canonical(result));
  ext_n = result.get_num();
  ext_d = result.get_den();
  included = is_included;
  return true;
}

template <typename ITV>
bool
Box<ITV>::max_min(const Linear_Expression& expr,
                  const bool maximize,
                  Coefficient& ext_n, Coefficient& ext_d,
                  bool& included,
                  Generator& g) const {
  if (!max_min(expr, maximize, ext_n, ext_d, included))
    return false;

  // Compute generator `g'.
  Linear_Expression g_expr;
  PPL_DIRTY_TEMP(Coefficient, g_divisor);
  g_divisor = 1;
  const int maximize_sign = maximize ? 1 : -1;
  PPL_DIRTY_TEMP0(mpq_class, g_coord);
  PPL_DIRTY_TEMP(Coefficient, num);
  PPL_DIRTY_TEMP(Coefficient, den);
  PPL_DIRTY_TEMP(Coefficient, lcm);
  PPL_DIRTY_TEMP(Coefficient, factor);
  for (dimension_type i = space_dimension(); i-- > 0; ) {
    const ITV& seq_i = seq[i];
    switch (sgn(expr.coefficient(Variable(i))) * maximize_sign) {
    case 1:
      assign_r(g_coord, seq_i.upper(), ROUND_NOT_NEEDED);
      break;
    case 0:
      // If 0 belongs to the interval, choose it
      // (and directly proceed to the next iteration).
      // FIXME: name qualification issue.
      if (seq_i.contains(0))
	continue;
      if (!seq_i.lower_is_unbounded())
	if (seq_i.lower_is_open())
	  if (!seq_i.upper_is_unbounded())
	    if (seq_i.upper_is_open()) {
	      // Bounded and open interval: compute middle point.
	      assign_r(g_coord, seq_i.lower(), ROUND_NOT_NEEDED);
	      PPL_DIRTY_TEMP0(mpq_class, q_seq_i_upper);
	      assign_r(q_seq_i_upper, seq_i.upper(), ROUND_NOT_NEEDED);
	      g_coord += q_seq_i_upper;
	      g_coord /= 2;
	    }
	    else
	      // The upper bound is in the interval.
	      assign_r(g_coord, seq_i.upper(), ROUND_NOT_NEEDED);
	  else {
	    // Lower is open, upper is unbounded.
	    assign_r(g_coord, seq_i.lower(), ROUND_NOT_NEEDED);
	    ++g_coord;
	  }
	else
	  // The lower bound is in the interval.
	  assign_r(g_coord, seq_i.lower(), ROUND_NOT_NEEDED);
      else {
	// Lower is unbounded, hence upper is bounded
	// (since we know that 0 does not belong to the interval).
	assert(!seq_i.upper_is_unbounded());
	assign_r(g_coord, seq_i.upper(), ROUND_NOT_NEEDED);
	if (seq_i.upper_is_open())
	  --g_coord;
      }
      break;
    case -1:
      assign_r(g_coord, seq_i.lower(), ROUND_NOT_NEEDED);
      break;
    }
    // Add g_coord * Variable(i) to the generator.
    assign_r(den, g_coord.get_den(), ROUND_NOT_NEEDED);
    lcm_assign(lcm, g_divisor, den);
    exact_div_assign(factor, lcm, g_divisor);
    g_expr *= factor;
    exact_div_assign(factor, lcm, den);
    assign_r(num, g_coord.get_num(), ROUND_NOT_NEEDED);
    num *= factor;
    g_expr += num * Variable(i);
    g_divisor = lcm;
  }
  g = Generator::point(g_expr, g_divisor);
  return true;
}

template <typename ITV>
bool
Box<ITV>::contains(const Box& y) const {
  const Box& x = *this;
  // Dimension-compatibility check.
  if (x.space_dimension() != y.space_dimension())
    x.throw_dimension_incompatible("contains(y)", y);

  // If `y' is empty, then `x' contains `y'.
  if (y.is_empty())
    return true;

  // If `x' is empty, then `x' cannot contain `y'.
  if (x.is_empty())
    return false;

  for (dimension_type k = x.seq.size(); k-- > 0; )
    // FIXME: fix this name qualification issue.
    if (!x.seq[k].contains(y.seq[k]))
      return false;
  return true;
}

template <typename ITV>
bool
Box<ITV>::is_disjoint_from(const Box& y) const {
  const Box& x = *this;
  // Dimension-compatibility check.
  if (x.space_dimension() != y.space_dimension())
    x.throw_dimension_incompatible("is_disjoint_from(y)", y);

  // If any of `x' or `y' is marked empty, then they are disjoint.
  // Note: no need to use `is_empty', as the following loop is anyway correct.
  if (x.marked_empty() || y.marked_empty())
    return true;

  for (dimension_type k = x.seq.size(); k-- > 0; )
    // FIXME: fix this name qualification issue.
    if (x.seq[k].is_disjoint_from(y.seq[k]))
      return true;
  return false;
}

template <typename ITV>
inline bool
Box<ITV>::upper_bound_assign_if_exact(const Box& y) {
  Box& x = *this;

  // Dimension-compatibility check.
  if (x.space_dimension() != y.space_dimension())
    x.throw_dimension_incompatible("upper_bound_assign_if_exact(y)", y);

  // The lub of a box with an empty box is equal to the first box.
  if (y.marked_empty())
    return true;
  if (x.marked_empty()) {
    x = y;
    return true;
  }

  bool x_j_does_not_contain_y_j = false;
  bool y_j_does_not_contain_x_j = false;

  for (dimension_type i = x.seq.size(); i-- > 0; ) {
    const ITV& x_seq_i = x.seq[i];
    const ITV& y_seq_i = y.seq[i];

    if (!x_seq_i.can_be_exactly_joined_to(y_seq_i))
      return false;

    // Note: the use of `y_i_does_not_contain_x_i' is needed
    // because we want to temporarily preserve the old value
    // of `y_j_does_not_contain_x_j'.
    bool y_i_does_not_contain_x_i = !y_seq_i.contains(x_seq_i);
    if (y_i_does_not_contain_x_i && x_j_does_not_contain_y_j)
      return false;
    if (!x_seq_i.contains(y_seq_i)) {
      if (y_j_does_not_contain_x_j)
        return false;
      else
        x_j_does_not_contain_y_j = true;
    }
    if (y_i_does_not_contain_x_i)
      y_j_does_not_contain_x_j = true;
  }

  // The upper bound is exact: compute it into *this.
  for (dimension_type k = x.seq.size(); k-- > 0; )
    x.seq[k].join_assign(y.seq[k]);
  return true;
}

template <typename ITV>
bool
Box<ITV>::OK() const {
  if (status.test_empty_up_to_date() && !status.test_empty()) {
    Box tmp = *this;
    tmp.reset_empty_up_to_date();
    if (tmp.check_empty()) {
#ifndef NDEBUG
      std::cerr << "The box is empty, but it is marked as non-empty."
		<< std::endl;
#endif // NDEBUG
      return false;
    }
  }

  // A box that is not marked empty must have meaningful intervals.
  if (!marked_empty()) {
    for (dimension_type k = seq.size(); k-- > 0; )
      if (!seq[k].OK())
	return false;
  }

  return true;
}

template <typename ITV>
dimension_type
Box<ITV>::affine_dimension() const {
  dimension_type d = space_dimension();
  // A zero-space-dim box always has affine dimension zero.
  if (d == 0)
    return 0;

  // An empty box has affine dimension zero.
  if (is_empty())
    return 0;

  for (dimension_type k = d; k-- > 0; )
    if (seq[k].is_singleton())
      --d;

  return d;
}

template <typename ITV>
bool
Box<ITV>::check_empty() const {
  assert(!marked_empty());
  Box<ITV>& x = const_cast<Box<ITV>&>(*this);
  for (dimension_type k = seq.size(); k-- > 0; )
    if (seq[k].is_empty()) {
      x.set_empty();
      return true;
    }
  x.set_nonempty();;
  return false;
}

template <typename ITV>
bool
Box<ITV>::is_universe() const {
  if (marked_empty())
    return false;
  for (dimension_type k = seq.size(); k-- > 0; )
    if (!seq[k].is_universe())
      return false;
  return true;
}

template <typename ITV>
bool
Box<ITV>::is_topologically_closed() const {
  if (!ITV::info_type::store_open || is_empty())
    return true;

  for (dimension_type k = seq.size(); k-- > 0; )
    if (!seq[k].is_topologically_closed())
      return false;
  return true;
}

template <typename ITV>
bool
Box<ITV>::is_discrete() const {
  if (is_empty())
    return true;
  for (dimension_type k = seq.size(); k-- > 0; )
    if (!seq[k].is_singleton())
      return false;
  return true;
}

template <typename ITV>
bool
Box<ITV>::is_bounded() const {
  if (is_empty())
    return true;
  for (dimension_type k = seq.size(); k-- > 0; )
    if (seq[k].is_unbounded())
      return false;
  return true;
}

template <typename ITV>
bool
Box<ITV>::contains_integer_point() const {
  if (marked_empty())
    return false;
  for (dimension_type k = seq.size(); k-- > 0; )
    if (!seq[k].contains_integer_point())
      return false;
  return true;
}

template <typename ITV>
bool
Box<ITV>::constrains(Variable var) const {
  // `var' should be one of the dimensions of the polyhedron.
  const dimension_type var_space_dim = var.space_dimension();
  if (space_dimension() < var_space_dim)
    throw_dimension_incompatible("constrains(v)", "v", var);

  if (marked_empty() || !seq[var_space_dim-1].is_universe())
    return true;
  // Now force an emptiness check.
  return is_empty();
}

template <typename ITV>
void
Box<ITV>::unconstrain(const Variables_Set& to_be_unconstrained) {
  // The cylindrification wrt no dimensions is a no-op.
  // This case also captures the only legal cylindrification
  // of a box in a 0-dim space.
  if (to_be_unconstrained.empty())
    return;

  // Dimension-compatibility check.
  const dimension_type min_space_dim = to_be_unconstrained.space_dimension();
  if (space_dimension() < min_space_dim)
    throw_dimension_incompatible("unconstrain(vs)", min_space_dim);

  // If the box is already empty, there is nothing left to do.
  if (marked_empty())
    return;

  // Here the box might still be empty (but we haven't detected it yet):
  // check emptiness of the interval for each of the variables in
  // `to_be_unconstrained' before cylindrification.
  for (Variables_Set::const_iterator tbu = to_be_unconstrained.begin(),
         tbu_end = to_be_unconstrained.end(); tbu != tbu_end; ++tbu) {
    ITV& seq_tbu = seq[*tbu];
    if (!seq_tbu.is_empty())
      seq_tbu.assign(UNIVERSE);
    else {
      set_empty();
      break;
    }
  }
  assert(OK());
}

template <typename ITV>
void
Box<ITV>::topological_closure_assign() {
  if (!ITV::info_type::store_open || is_empty())
    return;

  for (dimension_type k = seq.size(); k-- > 0; )
    seq[k].topological_closure_assign();
}

template <typename ITV>
void
Box<ITV>::intersection_assign(const Box& y) {
  Box& x = *this;
  const dimension_type space_dim = space_dimension();

  // Dimension-compatibility check.
  if (space_dim != y.space_dimension())
    x.throw_dimension_incompatible("intersection_assign(y)", y);

  // If one of the two boxes is empty, the intersection is empty.
  if (x.marked_empty())
    return;
  if (y.marked_empty()) {
    x.set_empty();
    return;
  }

  // If both boxes 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;

  // FIXME: here we may conditionally exploit a capability of the
  // underlying interval to eagerly detect empty results.
  reset_empty_up_to_date();

  for (dimension_type k = space_dim; k-- > 0; )
    x.seq[k].intersect_assign(y.seq[k]);

  assert(x.OK());
}

template <typename ITV>
void
Box<ITV>::upper_bound_assign(const Box& y) {
  Box& x = *this;

  // Dimension-compatibility check.
  if (x.space_dimension() != y.space_dimension())
    x.throw_dimension_incompatible("upper_bound_assign(y)", y);

  // The lub of a box with an empty box is equal to the first box.
  if (y.marked_empty())
    return;
  if (x.marked_empty()) {
    x = y;
    return;
  }

  for (dimension_type k = x.seq.size(); k-- > 0; )
    x.seq[k].join_assign(y.seq[k]);

  assert(x.OK());
}

template <typename ITV>
void
Box<ITV>::concatenate_assign(const Box& y) {
  Box& x = *this;
  const dimension_type x_space_dim = x.space_dimension();
  const dimension_type y_space_dim = y.space_dimension();

  // If `y' is marked empty, the result will be empty too.
  if (y.marked_empty())
    x.set_empty();

  // If `y' is a 0-dim space box, there is nothing left to do.
  if (y_space_dim == 0)
    return;

  // Here `y_space_dim > 0', so that a non-trivial concatenation will occur:
  // make sure that reallocation will occur once at most.
  x.seq.reserve(x_space_dim + y_space_dim);

  // If `x' is marked empty, then it is sufficient to adjust
  // the dimension of the vector space.
  if (x.marked_empty()) {
    x.seq.insert(x.seq.end(), y_space_dim, ITV(EMPTY));
    assert(x.OK());
    return;
  }

  // Here neither `x' nor `y' are marked empty: concatenate them.
  std::copy(y.seq.begin(), y.seq.end(),
	    std::back_insert_iterator<Sequence>(x.seq));
  // Update the `empty_up_to_date' flag.
  if (!y.status.test_empty_up_to_date())
    reset_empty_up_to_date();

  assert(x.OK());
}

template <typename ITV>
void
Box<ITV>::difference_assign(const Box& y) {
  const dimension_type space_dim = space_dimension();

  // Dimension-compatibility check.
  if (space_dim != y.space_dimension())
    throw_dimension_incompatible("difference_assign(y)", y);

  Box& x = *this;
  if (x.is_empty() || y.is_empty())
    return;

  switch (space_dim) {
  case 0:
    // If `x' is zero-dimensional, then at this point both `x' and `y'
    // are the universe box, so that their difference is empty.
    x.set_empty();
    break;

  case 1:
    x.seq[0].difference_assign(y.seq[0]);
    if (x.seq[0].is_empty())
      x.set_empty();
    break;

  default:
    {
      dimension_type index_non_contained = space_dim;
      dimension_type number_non_contained = 0;
      for (dimension_type i = space_dim; i-- > 0; )
        if (!y.seq[i].contains(x.seq[i])) {
          if (++number_non_contained == 1)
            index_non_contained = i;
          else
            break;
        }

      switch (number_non_contained) {
      case 0:
        // `y' covers `x': the difference is empty.
        x.set_empty();
        break;
      case 1:
        x.seq[index_non_contained]
          .difference_assign(y.seq[index_non_contained]);
        if (x.seq[index_non_contained].is_empty())
          x.set_empty();
        break;
      default:
        // Nothing to do: the difference is `x'.
        break;
      }
    }
    break;
  }
  assert(OK());
}

template <typename ITV>
bool
Box<ITV>::simplify_using_context_assign(const Box& y) {
  Box& x = *this;
  const dimension_type num_dims = x.space_dimension();
  // Dimension-compatibility check.
  if (num_dims != y.space_dimension())
    x.throw_dimension_incompatible("simplify_using_context_assign(y)", y);

  // Filter away the zero-dimensional case.
  if (num_dims == 0) {
    if (y.marked_empty()) {
      x.set_nonempty();
      return false;
    }
    else
      return !x.marked_empty();
  }

  // Filter away the case when `y' is empty.
  if (y.is_empty()) {
    for (dimension_type i = num_dims; i-- > 0; )
      x.seq[i].assign(UNIVERSE);
    x.set_nonempty();
    return false;
  }

  if (x.is_empty()) {
    // Find in `y' a non-universe interval, if any.
    for (dimension_type i = 0; i < num_dims; ++i) {
      if (y.seq[i].is_universe())
        x.seq[i].assign(UNIVERSE);
      else {
        // Set x.seq[i] so as to contradict y.seq[i], if possible.
        ITV& seq_i = x.seq[i];
        seq_i.empty_intersection_assign(y.seq[i]);
        if (seq_i.is_empty()) {
          // We were not able to assign to `seq_i' a non-empty interval:
          // reset `seq_i' to the universe interval and keep searching.
          seq_i.assign(UNIVERSE);
          continue;
        }
        // We assigned to `seq_i' a non-empty interval:
        // set the other intervals to universe and return.
        for (++i; i < num_dims; ++i)
          x.seq[i].assign(UNIVERSE);
        x.set_nonempty();
        assert(x.OK());
        return false;
      }
    }
    // All intervals in `y' are universe or could not be contradicted:
    // simplification can leave the empty box `x' as is.
    assert(x.OK() && x.is_empty());
    return false;
  }

  // Loop index `i' is intentionally going upwards.
  dimension_type i = 0;
  for ( ; i < num_dims; ++i) {
    if (!x.seq[i].simplify_using_context_assign(y.seq[i])) {
      assert(!x.seq[i].is_empty());
      // The intersection of `x' and `y' is empty due to the i-th interval:
      // reset other intervals to UNIVERSE.
      for (dimension_type j = num_dims; j-- > i; )
        x.seq[j].assign(UNIVERSE);
      for (dimension_type j = i; j-- > 0; )
        x.seq[j].assign(UNIVERSE);
      assert(x.OK());
      return false;
    }
  }
  assert(x.OK());
  return true;
}

template <typename ITV>
void
Box<ITV>::time_elapse_assign(const Box& y) {
  Box& x = *this;
  const dimension_type x_space_dim = x.space_dimension();

  // Dimension-compatibility check.
  if (x_space_dim != y.space_dimension())
    x.throw_dimension_incompatible("time_elapse_assign(y)", y);

  // Dealing with the zero-dimensional case.
  if (x_space_dim == 0) {
    if (y.marked_empty())
      x.set_empty();
    return;
  }

  // If either one of `x' or `y' is empty, the result is empty too.
  // Note: if possible, avoid cost of checking for emptiness.
  if (x.marked_empty() || y.marked_empty()
      || x.is_empty() || y.is_empty()) {
    x.set_empty();
    return;
  }

  for (dimension_type i = x_space_dim; i-- > 0; ) {
    ITV& x_seq_i = x.seq[i];
    const ITV& y_seq_i = y.seq[i];
    if (!x_seq_i.lower_is_unbounded())
      if (y_seq_i.lower_is_unbounded() || y_seq_i.lower() < 0)
	x_seq_i.lower_set(UNBOUNDED);
    if (!x_seq_i.upper_is_unbounded())
      if (y_seq_i.upper_is_unbounded() || y_seq_i.upper() > 0)
	x_seq_i.upper_set(UNBOUNDED);
  }
  assert(x.OK());
}

template <typename ITV>
inline void
Box<ITV>::remove_space_dimensions(const Variables_Set& to_be_removed) {
  // The removal of no dimensions from any box is a no-op.
  // Note that this case also captures the only legal removal of
  // space dimensions from a box in a zero-dimensional space.
  if (to_be_removed.empty()) {
    assert(OK());
    return;
  }

  const dimension_type old_space_dim = space_dimension();

  // Dimension-compatibility check.
  const dimension_type tbr_space_dim = to_be_removed.space_dimension();
  if (old_space_dim < tbr_space_dim)
    throw_dimension_incompatible("remove_space_dimensions(vs)",
				 tbr_space_dim);

  const dimension_type new_space_dim = old_space_dim - to_be_removed.size();

  // If the box is empty (this must be detected), then resizing is all
  // what is needed.  If it is not empty and we are removing _all_ the
  // dimensions then, again, resizing suffices.
  if (is_empty() || new_space_dim == 0) {
    seq.resize(new_space_dim);
    assert(OK());
    return;
  }

  // For each variable to be removed, we fill the corresponding interval
  // by shifting left those intervals that will not be removed.
  Variables_Set::const_iterator tbr = to_be_removed.begin();
  Variables_Set::const_iterator tbr_end = to_be_removed.end();
  dimension_type dst = *tbr;
  dimension_type src = dst + 1;
  for (++tbr; tbr != tbr_end; ++tbr) {
    const dimension_type tbr_next = *tbr;
    // All intervals in between are moved to the left.
    while (src < tbr_next)
      seq[dst++].swap(seq[src++]);
    ++src;
  }
  // Moving the remaining intervals.
  while (src < old_space_dim)
    seq[dst++].swap(seq[src++]);

  assert(dst == new_space_dim);
  seq.resize(new_space_dim);

  assert(OK());
}

template <typename ITV>
void
Box<ITV>::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.
  const dimension_type old_dim = space_dimension();
  if (new_dim > old_dim)
    throw_dimension_incompatible("remove_higher_space_dimensions(nd)",
				 new_dim);

  // The removal of no dimensions from any box is a no-op.
  // Note that this case also captures the only legal removal of
  // dimensions from a zero-dim space box.
  if (new_dim == old_dim) {
    assert(OK());
    return;
  }

  seq.erase(seq.begin() + new_dim, seq.end());
  assert(OK());
}

template <typename ITV>
template <typename Partial_Function>
void
Box<ITV>::map_space_dimensions(const Partial_Function& pfunc) {
  const dimension_type space_dim = space_dimension();
  if (space_dim == 0)
    return;

  if (pfunc.has_empty_codomain()) {
    // All dimensions vanish: the box becomes zero_dimensional.
    remove_higher_space_dimensions(0);
    return;
  }

  const dimension_type new_space_dim = pfunc.max_in_codomain() + 1;
  // If the box is empty, then simply adjust the space dimension.
  if (is_empty()) {
    remove_higher_space_dimensions(new_space_dim);
    return;
  }

  // We create a new Box with the new space dimension.
  Box<ITV> tmp(new_space_dim);
  // Map the intervals, exchanging the indexes.
  for (dimension_type i = 0; i < space_dim; ++i) {
    dimension_type new_i;
    if (pfunc.maps(i, new_i))
      seq[i].swap(tmp.seq[new_i]);
  }
  swap(tmp);
  assert(OK());
}

template <typename ITV>
void
Box<ITV>::fold_space_dimensions(const Variables_Set& to_be_folded,
                                const Variable var) {
  const dimension_type space_dim = space_dimension();
  // `var' should be one of the dimensions of the box.
  if (var.space_dimension() > space_dim)
    throw_dimension_incompatible("fold_space_dimensions(tbf, v)", "v", var);

  // The folding of no dimensions is a no-op.
  if (to_be_folded.empty())
    return;

  // All variables in `to_be_folded' should be dimensions of the box.
  if (to_be_folded.space_dimension() > space_dim)
    throw_dimension_incompatible("fold_space_dimensions(tbf, ...)",
				 to_be_folded.space_dimension());

  // Moreover, `var.id()' should not occur in `to_be_folded'.
  if (to_be_folded.find(var.id()) != to_be_folded.end())
    throw_generic("fold_space_dimensions(tbf, v)",
		  "v should not occur in tbf");

  // Note: the check for emptiness is needed for correctness.
  if (!is_empty()) {
    // Join the interval corresponding to variable `var' with the intervals
    // corresponding to the variables in `to_be_folded'.
    ITV& seq_v = seq[var.id()];
    for (Variables_Set::const_iterator i = to_be_folded.begin(),
	   tbf_end = to_be_folded.end(); i != tbf_end; ++i)
      seq_v.join_assign(seq[*i]);
  }
  remove_space_dimensions(to_be_folded);
}

template <typename ITV>
void
Box<ITV>::add_constraint_no_check(const Constraint& c) {
  const dimension_type c_space_dim = c.space_dimension();
  assert(c_space_dim <= space_dimension());

  dimension_type c_num_vars = 0;
  dimension_type c_only_var = 0;
  // Throw an exception if c is not an interval constraints.
  if (!extract_interval_constraint(c, c_space_dim, c_num_vars, c_only_var))
    throw_generic("add_constraint(c)", "c is not an interval constraint");

  // Throw an exception if c is a nontrivial strict constraint
  // and ITV does not support open boundaries.
  if (c.is_strict_inequality() && c_num_vars != 0
      && !Box::interval_type::info_type::store_open)
    throw_generic("add_constraint(c)", "c is a nontrivial strict constraint");

  // Avoid doing useless work if the box is known to be empty.
  if (marked_empty())
    return;

  const Coefficient& n = c.inhomogeneous_term();
  if (c_num_vars == 0) {
    // Dealing with a trivial constraint.
    if (n < 0
        || (c.is_equality() && n != 0)
	|| (c.is_strict_inequality() && n == 0))
      set_empty();
    return;
  }

  assert(c_num_vars == 1);
  const Coefficient& d = c.coefficient(Variable(c_only_var));
  add_interval_constraint_no_check(c_only_var, c.type(), n, d);
}

template <typename ITV>
void
Box<ITV>::add_constraints_no_check(const Constraint_System& cs) {
  assert(cs.space_dimension() <= space_dimension());
  // Note: even when the box is known to be empty, we need to go
  // through all the constraints to fulfill the method's contract
  // for what concerns exception throwing.
  for (Constraint_System::const_iterator i = cs.begin(),
	 cs_end = cs.end(); i != cs_end; ++i)
    add_constraint_no_check(*i);
  assert(OK());
}

template <typename ITV>
void
Box<ITV>::add_congruence_no_check(const Congruence& cg) {
  const dimension_type cg_space_dim = cg.space_dimension();
  assert(cg_space_dim <= space_dimension());

  // Set aside the case of proper congruences.
  if (cg.is_proper_congruence()) {
    if (cg.is_inconsistent()) {
      set_empty();
      return;
    }
    else if (cg.is_tautological())
      return;
    else
      // FIXME: what about intervals with restrictions?
      throw_generic("add_congruence(cg)",
                    "cg is a nontrivial proper congruence");
  }

  assert(cg.is_equality());
  dimension_type cg_num_vars = 0;
  dimension_type cg_only_var = 0;
  // Throw an exception if c is not an interval congruence.
  if (!extract_interval_congruence(cg, cg_space_dim, cg_num_vars, cg_only_var))
    throw_generic("add_congruence(cg)", "cg is not an interval congruence");

  // Avoid doing useless work if the box is known to be empty.
  if (marked_empty())
    return;

  const Coefficient& n = cg.inhomogeneous_term();
  if (cg_num_vars == 0) {
    // Dealing with a trivial equality congruence.
    if (n != 0)
      set_empty();
    return;
  }

  assert(cg_num_vars == 1);
  const Coefficient& d = cg.coefficient(Variable(cg_only_var));
  add_interval_constraint_no_check(cg_only_var, Constraint::EQUALITY, n, d);
}

template <typename ITV>
void
Box<ITV>::add_congruences_no_check(const Congruence_System& cgs) {
  assert(cgs.space_dimension() <= space_dimension());
  // Note: even when the box is known to be empty, we need to go
  // through all the congruences to fulfill the method's contract
  // for what concerns exception throwing.
  for (Congruence_System::const_iterator i = cgs.begin(),
	 cgs_end = cgs.end(); i != cgs_end; ++i)
    add_congruence_no_check(*i);
  assert(OK());
}

template <typename ITV>
void
Box<ITV>::refine_no_check(const Constraint& c) {
  const dimension_type c_space_dim = c.space_dimension();
  assert(c_space_dim <= space_dimension());
  assert(!marked_empty());

  dimension_type c_num_vars = 0;
  dimension_type c_only_var = 0;
  // Non-interval constraints are ignored.
  // FIXME: instead of ignoring, safely use propagate_no_check()
  // (i.e., ensuring that no termination problem can arise).
  if (!extract_interval_constraint(c, c_space_dim, c_num_vars, c_only_var))
    return;

  const Coefficient& n = c.inhomogeneous_term();
  if (c_num_vars == 0) {
    // Dealing with a trivial constraint.
    if (n < 0
        || (c.is_equality() && n != 0)
        || (c.is_strict_inequality() && n == 0))
      set_empty();
    return;
  }

  assert(c_num_vars == 1);
  const Coefficient& d = c.coefficient(Variable(c_only_var));
  add_interval_constraint_no_check(c_only_var, c.type(), n, d);
}

template <typename ITV>
void
Box<ITV>::refine_no_check(const Constraint_System& cs) {
  assert(cs.space_dimension() <= space_dimension());
  for (Constraint_System::const_iterator i = cs.begin(),
	 cs_end = cs.end(); !marked_empty() && i != cs_end; ++i)
    refine_no_check(*i);
  assert(OK());
}

template <typename ITV>
void
Box<ITV>::refine_no_check(const Congruence& cg) {
  assert(!marked_empty());

  const dimension_type cg_space_dim = cg.space_dimension();
  assert(cg_space_dim <= space_dimension());

  if (cg.is_proper_congruence()) {
    // FIXME: also deal with the case of interval with restrictions.
    // A proper congruences is also an interval constraint
    // if and only if it is trivial.
    if (cg.is_inconsistent())
      set_empty();
    return;
  }

  assert(cg.is_equality());
  dimension_type cg_num_vars = 0;
  dimension_type cg_only_var = 0;
  // Congruences that are not interval congruences are ignored.
  if (!extract_interval_congruence(cg, cg_space_dim, cg_num_vars, cg_only_var))
    return;

  if (cg_num_vars == 0) {
    // Dealing with a trivial congruence.
    if (cg.inhomogeneous_term() != 0)
      set_empty();
    return;
  }

  assert(cg_num_vars == 1);
  const Coefficient& n = cg.inhomogeneous_term();
  const Coefficient& d = cg.coefficient(Variable(cg_only_var));
  add_interval_constraint_no_check(cg_only_var, Constraint::EQUALITY, n, d);
}

template <typename ITV>
void
Box<ITV>::refine_no_check(const Congruence_System& cgs) {
  assert(cgs.space_dimension() <= space_dimension());
  for (Congruence_System::const_iterator i = cgs.begin(),
	 cgs_end = cgs.end(); !marked_empty() && i != cgs_end; ++i)
    refine_no_check(*i);
  assert(OK());
}

#if 1 // Alternative implementations for propagate_constraint_no_check.
namespace {

inline bool
propagate_constraint_check_result(Result r, Ternary& open) {
  switch (r) {
  case V_NEG_OVERFLOW:
  case V_POS_OVERFLOW:
  case V_UNKNOWN_NEG_OVERFLOW:
  case V_UNKNOWN_POS_OVERFLOW:
    return true;
  case V_LT:
  case V_GT:
    open = T_YES;
    return false;
  case V_LE:
  case V_GE:
    if (open == T_NO)
      open = T_MAYBE;
    return false;
  case V_EQ:
    return false;
  default:
    assert(false);
    return true;
  }
}

} // namespace

template <typename ITV>
void
Box<ITV>::propagate_constraint_no_check(const Constraint& c) {
  assert(c.space_dimension() <= space_dimension());

  typedef
    typename Select_Temp_Boundary_Type<typename ITV::boundary_type>::type
    Temp_Boundary_Type;

  const dimension_type c_space_dim = c.space_dimension();
  const Constraint::Type c_type = c.type();
  const Coefficient& c_inhomogeneous_term = c.inhomogeneous_term();

  // Find a space dimension having a non-zero coefficient (if any).
  dimension_type last_k = c_space_dim;
  for (dimension_type k = c_space_dim; k-- > 0; ) {
    if (c.coefficient(Variable(k)) != 0) {
      last_k = k;
      break;
    }
  }
  if (last_k == c_space_dim) {
    // Constraint c is trivial: check if it is inconsistent.
    if (c_inhomogeneous_term < 0
        || (c_inhomogeneous_term == 0
            && c_type != Constraint::NONSTRICT_INEQUALITY))
      set_empty();
    return;
  }

  // Here constraint c is non-trivial.
  assert(last_k < c_space_dim);
  Result r;
  Temp_Boundary_Type t_bound;
  Temp_Boundary_Type t_a;
  Temp_Boundary_Type t_x;
  Ternary open;
  for (dimension_type k = last_k+1; k-- > 0; ) {
    const Coefficient& a_k = c.coefficient(Variable(k));
    int sgn_a_k = sgn(a_k);
    if (sgn_a_k == 0)
      continue;
    if (sgn_a_k > 0) {
      open = (c_type == Constraint::STRICT_INEQUALITY) ? T_YES : T_NO;
      if (open == T_NO)
	maybe_reset_fpu_inexact<Temp_Boundary_Type>();
      r = assign_r(t_bound, c_inhomogeneous_term, ROUND_UP);
      if (propagate_constraint_check_result(r, open))
	goto maybe_refine_upper_1;
      r = neg_assign_r(t_bound, t_bound, ROUND_DOWN);
      if (propagate_constraint_check_result(r, open))
	goto maybe_refine_upper_1;
      for (dimension_type i = last_k+1; i-- > 0; ) {
	if (i == k)
	  continue;
	const Coefficient& a_i = c.coefficient(Variable(i));
	int sgn_a_i = sgn(a_i);
	if (sgn_a_i == 0)
	  continue;
	ITV& x_i = seq[i];
	if (sgn_a_i < 0) {
	  if (x_i.lower_is_unbounded())
	    goto maybe_refine_upper_1;
	  r = assign_r(t_a, a_i, ROUND_DOWN);
	  if (propagate_constraint_check_result(r, open))
	    goto maybe_refine_upper_1;
	  r = assign_r(t_x, x_i.lower(), ROUND_DOWN);
	  if (propagate_constraint_check_result(r, open))
	    goto maybe_refine_upper_1;
	  if (x_i.lower_is_open())
	    open = T_YES;
	  r = sub_mul_assign_r(t_bound, t_a, t_x, ROUND_DOWN);
	  if (propagate_constraint_check_result(r, open))
	    goto maybe_refine_upper_1;
	}
	else {
	  assert(sgn_a_i > 0);
	  if (x_i.upper_is_unbounded())
	    goto maybe_refine_upper_1;
	  r = assign_r(t_a, a_i, ROUND_UP);
	  if (propagate_constraint_check_result(r, open))
	    goto maybe_refine_upper_1;
	  r = assign_r(t_x, x_i.upper(), ROUND_UP);
	  if (propagate_constraint_check_result(r, open))
	    goto maybe_refine_upper_1;
	  if (x_i.upper_is_open())
	    open = T_YES;
	  r = sub_mul_assign_r(t_bound, t_a, t_x, ROUND_DOWN);
	  if (propagate_constraint_check_result(r, open))
	    goto maybe_refine_upper_1;
	}
      }
      r = assign_r(t_a, a_k, ROUND_UP);
      if (propagate_constraint_check_result(r, open))
	goto maybe_refine_upper_1;
      r = div_assign_r(t_bound, t_bound, t_a, ROUND_DOWN);
      if (propagate_constraint_check_result(r, open))
	goto maybe_refine_upper_1;

      // Refine the lower bound of `seq[k]' with `t_bound'.
      if (open == T_MAYBE
	  && maybe_check_fpu_inexact<Temp_Boundary_Type>() == 1)
	open = T_YES;
      seq[k].lower_narrow(t_bound, open == T_YES);
      reset_empty_up_to_date();
    maybe_refine_upper_1:
      if (c_type != Constraint::EQUALITY)
	continue;
      open = T_NO;
      maybe_reset_fpu_inexact<Temp_Boundary_Type>();
      r = assign_r(t_bound, c_inhomogeneous_term, ROUND_DOWN);
      if (propagate_constraint_check_result(r, open))
	goto next_k;
      r = neg_assign_r(t_bound, t_bound, ROUND_UP);
      if (propagate_constraint_check_result(r, open))
	goto next_k;
      for (dimension_type i = c_space_dim; i-- > 0; ) {
	if (i == k)
	  continue;
	const Coefficient& a_i = c.coefficient(Variable(i));
	int sgn_a_i = sgn(a_i);
	if (sgn_a_i == 0)
	  continue;
	ITV& x_i = seq[i];
	if (sgn_a_i < 0) {
	  if (x_i.upper_is_unbounded())
	    goto next_k;
	  r = assign_r(t_a, a_i, ROUND_UP);
	  if (propagate_constraint_check_result(r, open))
	    goto next_k;
	  r = assign_r(t_x, x_i.upper(), ROUND_UP);
	  if (propagate_constraint_check_result(r, open))
	    goto next_k;
	  if (x_i.upper_is_open())
	    open = T_YES;
	  r = sub_mul_assign_r(t_bound, t_a, t_x, ROUND_UP);
	  if (propagate_constraint_check_result(r, open))
	    goto next_k;
	}
	else {
	  assert(sgn_a_i > 0);
	  if (x_i.lower_is_unbounded())
	    goto next_k;
	  r = assign_r(t_a, a_i, ROUND_DOWN);
	  if (propagate_constraint_check_result(r, open))
	    goto next_k;
	  r = assign_r(t_x, x_i.lower(), ROUND_DOWN);
	  if (propagate_constraint_check_result(r, open))
	    goto next_k;
	  if (x_i.lower_is_open())
	    open = T_YES;
	  r = sub_mul_assign_r(t_bound, t_a, t_x, ROUND_UP);
	  if (propagate_constraint_check_result(r, open))
	    goto next_k;
	}
      }
      r = assign_r(t_a, a_k, ROUND_DOWN);
      if (propagate_constraint_check_result(r, open))
	goto next_k;
      r = div_assign_r(t_bound, t_bound, t_a, ROUND_UP);
      if (propagate_constraint_check_result(r, open))
	goto next_k;

      // Refine the upper bound of seq[k] with t_bound.
      if (open == T_MAYBE
	  && maybe_check_fpu_inexact<Temp_Boundary_Type>() == 1)
	open = T_YES;
      seq[k].upper_narrow(t_bound, open == T_YES);
      reset_empty_up_to_date();
    }
    else {
      assert(sgn_a_k < 0);
      open = (c_type == Constraint::STRICT_INEQUALITY) ? T_YES : T_NO;
      if (open == T_NO)
	maybe_reset_fpu_inexact<Temp_Boundary_Type>();
      r = assign_r(t_bound, c_inhomogeneous_term, ROUND_UP);
      if (propagate_constraint_check_result(r, open))
	goto maybe_refine_upper_2;
      r = neg_assign_r(t_bound, t_bound, ROUND_DOWN);
      if (propagate_constraint_check_result(r, open))
	goto maybe_refine_upper_2;
      for (dimension_type i = c_space_dim; i-- > 0; ) {
	if (i == k)
	  continue;
	const Coefficient& a_i = c.coefficient(Variable(i));
	int sgn_a_i = sgn(a_i);
	if (sgn_a_i == 0)
	  continue;
	ITV& x_i = seq[i];
	if (sgn_a_i < 0) {
	  if (x_i.lower_is_unbounded())
	    goto maybe_refine_upper_2;
	  r = assign_r(t_a, a_i, ROUND_DOWN);
	  if (propagate_constraint_check_result(r, open))
	    goto maybe_refine_upper_2;
	  r = assign_r(t_x, x_i.lower(), ROUND_DOWN);
	  if (propagate_constraint_check_result(r, open))
	    goto maybe_refine_upper_2;
	  if (x_i.lower_is_open())
	    open = T_YES;
	  r = sub_mul_assign_r(t_bound, t_a, t_x, ROUND_UP);
	  if (propagate_constraint_check_result(r, open))
	    goto maybe_refine_upper_2;
	}
	else {
	  assert(sgn_a_i > 0);
	  if (x_i.upper_is_unbounded())
	    goto maybe_refine_upper_2;
	  r = assign_r(t_a, a_i, ROUND_UP);
	  if (propagate_constraint_check_result(r, open))
	    goto maybe_refine_upper_2;
	  r = assign_r(t_x, x_i.upper(), ROUND_UP);
	  if (propagate_constraint_check_result(r, open))
	    goto maybe_refine_upper_2;
	  if (x_i.upper_is_open())
	    open = T_YES;
	  r = sub_mul_assign_r(t_bound, t_a, t_x, ROUND_DOWN);
	  if (propagate_constraint_check_result(r, open))
	    goto maybe_refine_upper_2;
	}
      }
      r = assign_r(t_a, a_k, ROUND_UP);
      if (propagate_constraint_check_result(r, open))
	goto maybe_refine_upper_2;
      r = div_assign_r(t_bound, t_bound, t_a, ROUND_UP);
      if (propagate_constraint_check_result(r, open))
	goto maybe_refine_upper_2;

      // Refine the upper bound of seq[k] with t_bound.
      if (open == T_MAYBE
	  && maybe_check_fpu_inexact<Temp_Boundary_Type>() == 1)
	open = T_YES;
      seq[k].upper_narrow(t_bound, open == T_YES);
      reset_empty_up_to_date();
    maybe_refine_upper_2:
      if (c_type != Constraint::EQUALITY)
	continue;
      open = T_NO;
      maybe_reset_fpu_inexact<Temp_Boundary_Type>();
      r = assign_r(t_bound, c_inhomogeneous_term, ROUND_DOWN);
      if (propagate_constraint_check_result(r, open))
	goto next_k;
      r = neg_assign_r(t_bound, t_bound, ROUND_UP);
      if (propagate_constraint_check_result(r, open))
	goto next_k;
      for (dimension_type i = c_space_dim; i-- > 0; ) {
	if (i == k)
	  continue;
	const Coefficient& a_i = c.coefficient(Variable(i));
	int sgn_a_i = sgn(a_i);
	if (sgn_a_i == 0)
	  continue;
	ITV& x_i = seq[i];
	if (sgn_a_i < 0) {
	  if (x_i.upper_is_unbounded())
	    goto next_k;
	  r = assign_r(t_a, a_i, ROUND_UP);
	  if (propagate_constraint_check_result(r, open))
	    goto next_k;
	  r = assign_r(t_x, x_i.upper(), ROUND_UP);
	  if (propagate_constraint_check_result(r, open))
	    goto next_k;
	  if (x_i.upper_is_open())
	    open = T_YES;
	  r = sub_mul_assign_r(t_bound, t_a, t_x, ROUND_UP);
	  if (propagate_constraint_check_result(r, open))
	    goto next_k;
	}
	else {
	  assert(sgn_a_i > 0);
	  if (x_i.lower_is_unbounded())
	    goto next_k;
	  r = assign_r(t_a, a_i, ROUND_DOWN);
	  if (propagate_constraint_check_result(r, open))
	    goto next_k;
	  r = assign_r(t_x, x_i.lower(), ROUND_DOWN);
	  if (propagate_constraint_check_result(r, open))
	    goto next_k;
	  if (x_i.lower_is_open())
	    open = T_YES;
	  r = sub_mul_assign_r(t_bound, t_a, t_x, ROUND_UP);
	  if (propagate_constraint_check_result(r, open))
	    goto next_k;
	}
      }
      r = assign_r(t_a, a_k, ROUND_DOWN);
      if (propagate_constraint_check_result(r, open))
	goto next_k;
      r = div_assign_r(t_bound, t_bound, t_a, ROUND_DOWN);
      if (propagate_constraint_check_result(r, open))
	goto next_k;

      // Refine the lower bound of seq[k] with t_bound.
      if (open == T_MAYBE
	  && maybe_check_fpu_inexact<Temp_Boundary_Type>() == 1)
	open = T_YES;
      seq[k].lower_narrow(t_bound, open == T_YES);
      reset_empty_up_to_date();
    }
  next_k:
    ;
  }
}

#else // Alternative implementations for propagate_constraint_no_check.

template <typename ITV>
void
Box<ITV>::propagate_constraint_no_check(const Constraint& c) {
  assert(c.space_dimension() <= space_dimension());

  dimension_type c_space_dim = c.space_dimension();
  ITV k[c_space_dim];
  ITV p[c_space_dim];
  for (dimension_type i = c_space_dim; i-- > 0; ) {
    k[i] = c.coefficient(Variable(i));
    ITV& p_i = p[i];
    p_i = seq[i];
    p_i.mul_assign(p_i, k[i]);
  }
  const Coefficient& inhomogeneous_term = c.inhomogeneous_term();
  for (dimension_type i = c_space_dim; i-- > 0; ) {
    int sgn_coefficient_i = sgn(c.coefficient(Variable(i)));
    if (sgn_coefficient_i == 0)
      continue;
    ITV q(inhomogeneous_term);
    for (dimension_type j = c_space_dim; j-- > 0; ) {
      if (i == j)
	continue;
      q.add_assign(q, p[j]);
    }
    q.div_assign(q, k[i]);
    q.neg_assign(q);
    Relation_Symbol rel;
    switch (c.type()) {
    case Constraint::EQUALITY:
      rel = EQUAL;
      break;
    case Constraint::NONSTRICT_INEQUALITY:
      rel = (sgn_coefficient_i > 0) ? GREATER_OR_EQUAL : LESS_OR_EQUAL;
      break;
    case Constraint::STRICT_INEQUALITY:
      rel = (sgn_coefficient_i > 0) ? GREATER_THAN : LESS_THAN;
      break;
    }
    seq[i].refine_existential(rel, q);
    // FIXME: could/should we exploit the return value of refine_existential,
    //        in case it is available?
    // FIMXE: should we instead be lazy and do not even bother about
    //        the possibility the interval becomes empty apart from setting
    //        empty_up_to_date = false?
    if (seq[i].is_empty()) {
      set_empty();
      break;
    }
  }

  assert(OK());
}

#endif // Alternative implementations for propagate_constraint_no_check.

template <typename ITV>
void
Box<ITV>::propagate_constraints_no_check(const Constraint_System& cs) {
  assert(cs.space_dimension() <= space_dimension());

  bool changed;
  do {
    Sequence copy(seq);
    for (Constraint_System::const_iterator i = cs.begin(),
	   cs_end = cs.end(); i != cs_end; ++i)
      propagate_constraint_no_check(*i);

    // Check if the client has requested abandoning all expensive
    // computations.  If so, the exception specified by the client
    // is thrown now.
    maybe_abandon();

    changed = (copy != seq);
  } while (changed);
}

template <typename ITV>
void
Box<ITV>::affine_image(const Variable var,
                       const Linear_Expression& expr,
                       Coefficient_traits::const_reference denominator) {
  // The denominator cannot be zero.
  if (denominator == 0)
    throw_generic("affine_image(v, e, d)", "d == 0");

  // Dimension-compatibility checks.
  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 polyhedron.
  const dimension_type var_space_dim = var.space_dimension();
  if (space_dim < var_space_dim)
    throw_dimension_incompatible("affine_image(v, e, d)", "v", var);

  if (is_empty())
    return;

  Tmp_Interval_Type expr_value, temp0, temp1;
  expr_value.assign(expr.inhomogeneous_term());
  for (dimension_type i = expr_space_dim; i-- > 0; ) {
    const Coefficient& coeff = expr.coefficient(Variable(i));
    if (coeff != 0) {
      temp0.assign(coeff);
      temp1.assign(seq[i]);
      temp0.mul_assign(temp0, temp1);
      expr_value.add_assign(expr_value, temp0);
    }
  }
  if (denominator != 1) {
    temp0.assign(denominator);
    expr_value.div_assign(expr_value, temp0);
  }
  seq[var.id()].assign(expr_value);

  assert(OK());
}

template <typename ITV>
void
Box<ITV>::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.
  const dimension_type x_space_dim = space_dimension();
  const dimension_type expr_space_dim = expr.space_dimension();
  if (x_space_dim < expr_space_dim)
    throw_dimension_incompatible("affine_preimage(v, e, d)", "e", expr);
  // `var' should be one of the dimensions of the polyhedron.
  const dimension_type var_space_dim = var.space_dimension();
  if (x_space_dim < var_space_dim)
    throw_dimension_incompatible("affine_preimage(v, e, d)", "v", var);

  if (is_empty())
    return;

  const Coefficient& expr_v = expr.coefficient(var);
  const bool invertible = (expr_v != 0);
  if (!invertible) {
    Tmp_Interval_Type expr_value, temp0, temp1;
    expr_value.assign(expr.inhomogeneous_term());
    for (dimension_type i = expr_space_dim; i-- > 0; ) {
      const Coefficient& coeff = expr.coefficient(Variable(i));
      if (coeff != 0) {
	temp0.assign(coeff);
	temp1.assign(seq[i]);
	temp0.mul_assign(temp0, temp1);
	expr_value.add_assign(expr_value, temp0);
      }
    }
    if (denominator != 1) {
      temp0.assign(denominator);
      expr_value.div_assign(expr_value, temp0);
    }
    ITV& x_seq_v = seq[var.id()];
    expr_value.intersect_assign(x_seq_v);
    if (expr_value.is_empty())
      set_empty();
    else
      x_seq_v.assign(UNIVERSE);
  }
  else {
    // The affine transformation is invertible.
    // CHECKME: for efficiency, would it be meaningful to avoid
    // the computation of inverse by partially evaluating the call
    // to affine_image?
    Linear_Expression inverse;
    inverse -= expr;
    inverse += (expr_v + denominator) * var;
    affine_image(var, inverse, expr_v);
  }
  assert(OK());
}

template <typename ITV>
void
Box<ITV>
::bounded_affine_image(const Variable var,
                       const Linear_Expression& lb_expr,
                       const Linear_Expression& ub_expr,
                       Coefficient_traits::const_reference denominator) {
  // The denominator cannot be zero.
  if (denominator == 0)
    throw_generic("bounded_affine_image(v, lb, ub, d)", "d == 0");

  // Dimension-compatibility checks.
  const dimension_type space_dim = space_dimension();
  // The dimension of `lb_expr' and `ub_expr' should not be
  // greater than the dimension of `*this'.
  const dimension_type lb_space_dim = lb_expr.space_dimension();
  if (space_dim < lb_space_dim)
    throw_dimension_incompatible("bounded_affine_image(v, lb, ub, d)",
				 "lb", lb_expr);
  const dimension_type ub_space_dim = ub_expr.space_dimension();
  if (space_dim < ub_space_dim)
    throw_dimension_incompatible("bounded_affine_image(v, lb, ub, d)",
				 "ub", ub_expr);
    // `var' should be one of the dimensions of the box.
  const dimension_type var_space_dim = var.space_dimension();
  if (space_dim < var_space_dim)
    throw_dimension_incompatible("affine_image(v, e, d)", "v", var);

  // Any image of an empty box is empty.
  if (is_empty())
    return;

  // Add the constraint implied by the `lb_expr' and `ub_expr'.
  if (denominator > 0)
    refine_with_constraint(lb_expr <= ub_expr);
  else
    refine_with_constraint(lb_expr >= ub_expr);

  // Check whether `var' occurs in `lb_expr' and/or `ub_expr'.
  if (lb_expr.coefficient(var) == 0) {
    // Here `var' can only occur in `ub_expr'.
    generalized_affine_image(var,
			     LESS_OR_EQUAL,
			     ub_expr,
			     denominator);
    if (denominator > 0)
      refine_with_constraint(lb_expr <= denominator*var);
    else
      refine_with_constraint(denominator*var <= lb_expr);
  }
  else if (ub_expr.coefficient(var) == 0) {
    // Here `var' can only occur in `lb_expr'.
    generalized_affine_image(var,
			     GREATER_OR_EQUAL,
			     lb_expr,
			     denominator);
    if (denominator > 0)
      refine_with_constraint(denominator*var <= ub_expr);
    else
      refine_with_constraint(ub_expr <= denominator*var);
  }
  else {
    // Here `var' occurs in both `lb_expr' and `ub_expr'.  As boxes
    // can only use the non-relational constraints, we find the
    // maximum/minimum values `ub_expr' and `lb_expr' obtain with the
    // box and use these instead of the `ub-expr' and `lb-expr'.
    PPL_DIRTY_TEMP(Coefficient, max_num);
    PPL_DIRTY_TEMP(Coefficient, max_den);
    bool max_included;
    PPL_DIRTY_TEMP(Coefficient, min_num);
    PPL_DIRTY_TEMP(Coefficient, min_den);
    bool min_included;
    ITV& seq_v = seq[var.id()];
    if (maximize(ub_expr, max_num, max_den, max_included)) {
      if (minimize(lb_expr, min_num, min_den, min_included)) {
	// The `ub_expr' has a maximum value and the `lb_expr'
	// has a minimum value for the box.
	// Set the bounds for `var' using the minimum for `lb_expr'.
	min_den *= denominator;
	PPL_DIRTY_TEMP0(mpq_class, q);
	assign_r(q.get_num(), min_num, ROUND_NOT_NEEDED);
	assign_r(q.get_den(), min_den, ROUND_NOT_NEEDED);
	q.canonicalize();
	(denominator > 0)
	  ? seq_v.lower_set(q, !min_included)
	  : seq_v.upper_set(q, !min_included);
	// Now make the maximum of lb_expr the upper bound.  If the
	// maximum is not at a box point, then inequality is strict.
	max_den *= denominator;
	assign_r(q.get_num(), max_num, ROUND_NOT_NEEDED);
	assign_r(q.get_den(), max_den, ROUND_NOT_NEEDED);
	q.canonicalize();
	(denominator > 0)
	  ? seq_v.upper_set(q, !max_included)
	  : seq_v.lower_set(q, !max_included);
      }
      else {
	// The `ub_expr' has a maximum value but the `lb_expr'
	// has no minimum value for the box.
	// Set the bounds for `var' using the maximum for `lb_expr'.
	PPL_DIRTY_TEMP0(mpq_class, q);
	max_den *= denominator;
	assign_r(q.get_num(), max_num, ROUND_NOT_NEEDED);
	assign_r(q.get_den(), max_den, ROUND_NOT_NEEDED);
	q.canonicalize();
	if (denominator > 0) {
	  seq_v.lower_set(UNBOUNDED);
	  seq_v.upper_set(q, !max_included);
	}
	else {
	  seq_v.upper_set(UNBOUNDED);
	  seq_v.lower_set(q, !max_included);
	}
      }
    }
    else if (minimize(lb_expr, min_num, min_den, min_included)) {
	// The `ub_expr' has no maximum value but the `lb_expr'
	// has a minimum value for the box.
	// Set the bounds for `var' using the minimum for `lb_expr'.
	min_den *= denominator;
	PPL_DIRTY_TEMP0(mpq_class, q);
	assign_r(q.get_num(), min_num, ROUND_NOT_NEEDED);
	assign_r(q.get_den(), min_den, ROUND_NOT_NEEDED);
	q.canonicalize();
	if (denominator > 0) {
	  seq_v.upper_set(UNBOUNDED);
	  seq_v.lower_set(q, !min_included);
	}
	else {
	  seq_v.lower_set(UNBOUNDED);
	  seq_v.upper_set(q, !min_included);
	}
    }
    else {
      // The `ub_expr' has no maximum value and the `lb_expr'
      // has no minimum value for the box.
      // So we set the bounds to be unbounded.
      seq_v.upper_set(UNBOUNDED);
      seq_v.lower_set(UNBOUNDED);
    }
  }
  assert(OK());
}

template <typename ITV>
void
Box<ITV>
::bounded_affine_preimage(const Variable var,
                          const Linear_Expression& lb_expr,
                          const Linear_Expression& ub_expr,
                          Coefficient_traits::const_reference denominator) {
  // The denominator cannot be zero.
  const dimension_type space_dim = space_dimension();
  if (denominator == 0)
    throw_generic("bounded_affine_preimage(v, lb, ub, d)", "d == 0");

  // Dimension-compatibility checks.
  // `var' should be one of the dimensions of the polyhedron.
  const dimension_type var_space_dim = var.space_dimension();
  if (space_dim < var_space_dim)
    throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub, d)",
				 "v", var);
  // The dimension of `lb_expr' and `ub_expr' should not be
  // greater than the dimension of `*this'.
  const dimension_type lb_space_dim = lb_expr.space_dimension();
  if (space_dim < lb_space_dim)
    throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub)",
				 "lb", lb_expr);
  const dimension_type ub_space_dim = ub_expr.space_dimension();
  if (space_dim < ub_space_dim)
    throw_dimension_incompatible("bounded_affine_preimage(v, lb, ub)",
				 "ub", ub_expr);

  // Any preimage of an empty polyhedron is empty.
  if (marked_empty())
    return;

  const bool negative_denom = (denominator < 0);
  const Coefficient& lb_var_coeff = lb_expr.coefficient(var);
  const Coefficient& ub_var_coeff = ub_expr.coefficient(var);

  // If the implied constraint between `ub_expr and `lb_expr' is
  // independent of `var', then impose it now.
  if (lb_var_coeff == ub_var_coeff) {
    if (negative_denom)
      refine_with_constraint(lb_expr >= ub_expr);
    else
      refine_with_constraint(lb_expr <= ub_expr);
  }

  ITV& seq_var = seq[var.id()];
  if (!seq_var.is_universe()) {
    // We want to work with a positive denominator,
    // so the sign and its (unsigned) value are separated.
    PPL_DIRTY_TEMP_COEFFICIENT(pos_denominator);
    pos_denominator = denominator;
    if (negative_denom)
      neg_assign(pos_denominator, pos_denominator);
    // Store all the information about the upper and lower bounds
    // for `var' before making this interval unbounded.
    bool open_lower = seq_var.lower_is_open();
    bool unbounded_lower = seq_var.lower_is_unbounded();
    PPL_DIRTY_TEMP0(mpq_class, q_seq_var_lower);
    PPL_DIRTY_TEMP(Coefficient, num_lower);
    PPL_DIRTY_TEMP(Coefficient, den_lower);
    if (!unbounded_lower) {
      assign_r(q_seq_var_lower, seq_var.lower(), ROUND_NOT_NEEDED);
      assign_r(num_lower, q_seq_var_lower.get_num(), ROUND_NOT_NEEDED);
      assign_r(den_lower, q_seq_var_lower.get_den(), ROUND_NOT_NEEDED);
      if (negative_denom)
        neg_assign(den_lower, den_lower);
      num_lower *= pos_denominator;
      seq_var.lower_set(UNBOUNDED);
    }
    bool open_upper = seq_var.upper_is_open();
    bool unbounded_upper = seq_var.upper_is_unbounded();
    PPL_DIRTY_TEMP0(mpq_class, q_seq_var_upper);
    PPL_DIRTY_TEMP(Coefficient, num_upper);
    PPL_DIRTY_TEMP(Coefficient, den_upper);
    if (!unbounded_upper) {
      assign_r(q_seq_var_upper, seq_var.upper(), ROUND_NOT_NEEDED);
      assign_r(num_upper, q_seq_var_upper.get_num(), ROUND_NOT_NEEDED);
      assign_r(den_upper, q_seq_var_upper.get_den(), ROUND_NOT_NEEDED);
      if (negative_denom)
        neg_assign(den_upper, den_upper);
      num_upper *= pos_denominator;
      seq_var.upper_set(UNBOUNDED);
    }

    if (!unbounded_lower) {
      // `lb_expr' is revised by removing the `var' component,
      // multiplying by `-' denominator of the lower bound for `var',
      // and adding the lower bound for `var' to the inhomogeneous term.
      Linear_Expression revised_lb_expr(ub_expr);
      revised_lb_expr -= ub_var_coeff * var;
      PPL_DIRTY_TEMP(Coefficient, d);
      neg_assign(d, den_lower);
      revised_lb_expr *= d;
      revised_lb_expr += num_lower;

      // Find the minimum value for the revised lower bound expression
      // and use this to refine the appropriate bound.
      bool included;
      PPL_DIRTY_TEMP(Coefficient, den);
      if (minimize(revised_lb_expr, num_lower, den, included)) {
        den_lower *= (den * ub_var_coeff);
        PPL_DIRTY_TEMP0(mpq_class, q);
        assign_r(q.get_num(), num_lower, ROUND_NOT_NEEDED);
        assign_r(q.get_den(), den_lower, ROUND_NOT_NEEDED);
        q.canonicalize();
        open_lower |= !included;
        if ((ub_var_coeff >= 0) ? !negative_denom : negative_denom)
          seq_var.lower_narrow(q, open_lower);
        else
          seq_var.upper_narrow(q, open_lower);
        if (seq_var.is_empty()) {
          set_empty();
          return;
        }
      }
    }

    if (!unbounded_upper) {
      // `ub_expr' is revised by removing the `var' component,
      // multiplying by `-' denominator of the upper bound for `var',
      // and adding the upper bound for `var' to the inhomogeneous term.
      Linear_Expression revised_ub_expr(lb_expr);
      revised_ub_expr -= lb_var_coeff * var;
      PPL_DIRTY_TEMP(Coefficient, d);
      neg_assign(d, den_upper);
      revised_ub_expr *= d;
      revised_ub_expr += num_upper;

      // Find the maximum value for the revised upper bound expression
      // and use this to refine the appropriate bound.
      bool included;
      PPL_DIRTY_TEMP(Coefficient, den);
      if (maximize(revised_ub_expr, num_upper, den, included)) {
        den_upper *= (den * lb_var_coeff);
        PPL_DIRTY_TEMP0(mpq_class, q);
        assign_r(q.get_num(), num_upper, ROUND_NOT_NEEDED);
        assign_r(q.get_den(), den_upper, ROUND_NOT_NEEDED);
        q.canonicalize();
        open_upper |= !included;
        if ((lb_var_coeff >= 0) ? !negative_denom : negative_denom)
          seq_var.upper_narrow(q, open_upper);
        else
          seq_var.lower_narrow(q, open_upper);
        if (seq_var.is_empty()) {
          set_empty();
          return;
        }
      }
    }
  }

  // If the implied constraint between `ub_expr and `lb_expr' is
  // dependent on `var', then impose on the new box.
  if (lb_var_coeff != ub_var_coeff) {
    if (denominator > 0)
      refine_with_constraint(lb_expr <= ub_expr);
    else
      refine_with_constraint(lb_expr >= ub_expr);
  }

  assert(OK());
}

template <typename ITV>
void
Box<ITV>
::generalized_affine_image(const Variable var,
                           const Relation_Symbol relsym,
                           const Linear_Expression& expr,
                           Coefficient_traits::const_reference denominator) {
  // The denominator cannot be zero.
  if (denominator == 0)
    throw_generic("generalized_affine_image(v, r, e, d)", "d == 0");

  // Dimension-compatibility checks.
  const dimension_type space_dim = space_dimension();
  // The dimension of `expr' should not be greater than the dimension
  // of `*this'.
  if (space_dim < expr.space_dimension())
    throw_dimension_incompatible("generalized_affine_image(v, r, e, d)",
				 "e", expr);
  // `var' should be one of the dimensions of the box.
  const dimension_type var_space_dim = var.space_dimension();
  if (space_dim < var_space_dim)
    throw_dimension_incompatible("generalized_affine_image(v, r, e, d)",
				 "v", var);

  // The relation symbol cannot be a disequality.
  if (relsym == NOT_EQUAL)
    throw_generic("generalized_affine_image(v, r, e, d)",
		  "r is the disequality relation symbol");

  // First compute the affine image.
  affine_image(var, expr, denominator);

  if (relsym == EQUAL)
    // The affine relation is indeed an affine function.
    return;

  // Any image of an empty box is empty.
  if (is_empty())
    return;

  ITV& seq_var = seq[var.id()];
  switch (relsym) {
  case LESS_OR_EQUAL:
    seq_var.lower_set(UNBOUNDED);
    break;
  case LESS_THAN:
    seq_var.lower_set(UNBOUNDED);
    if (!seq_var.upper_is_unbounded())
      seq_var.refine_existential(LESS_THAN, seq_var.upper());
    break;
  case GREATER_OR_EQUAL:
    seq_var.upper_set(UNBOUNDED);
    break;
  case GREATER_THAN:
    seq_var.upper_set(UNBOUNDED);
    if (!seq_var.lower_is_unbounded())
      seq_var.refine_existential(GREATER_THAN, seq_var.lower());
    break;
  default:
    // The EQUAL and NOT_EQUAL cases have been already dealt with.
    throw std::runtime_error("PPL internal error");
  }
  assert(OK());
}

template <typename ITV>
void
Box<ITV>
::generalized_affine_preimage(const Variable var,
                              const Relation_Symbol relsym,
                              const Linear_Expression& expr,
                              Coefficient_traits::const_reference denominator)
{
  // The denominator cannot be zero.
  if (denominator == 0)
    throw_generic("generalized_affine_preimage(v, r, e, d)",
			   "d == 0");

  // Dimension-compatibility checks.
  const dimension_type space_dim = space_dimension();
  // The dimension of `expr' should not be greater than the dimension
  // of `*this'.
  if (space_dim < expr.space_dimension())
    throw_dimension_incompatible("generalized_affine_preimage(v, r, e, d)",
				 "e", expr);
  // `var' should be one of the dimensions of the box.
  const dimension_type var_space_dim = var.space_dimension();
  if (space_dim < var_space_dim)
    throw_dimension_incompatible("generalized_affine_preimage(v, r, e, d)",
				 "v", var);
  // The relation symbol cannot be a disequality.
  if (relsym == NOT_EQUAL)
    throw_generic("generalized_affine_preimage(v, r, e, d)",
                  "r is the disequality relation symbol");

  // Check whether the affine relation is indeed an affine function.
  if (relsym == EQUAL) {
    affine_preimage(var, expr, denominator);
    return;
  }

  // Compute the reversed relation symbol to simplify later coding.
  Relation_Symbol reversed_relsym;
  switch (relsym) {
  case LESS_THAN:
    reversed_relsym = GREATER_THAN;
    break;
  case LESS_OR_EQUAL:
    reversed_relsym = GREATER_OR_EQUAL;
    break;
  case GREATER_OR_EQUAL:
    reversed_relsym = LESS_OR_EQUAL;
    break;
  case GREATER_THAN:
    reversed_relsym = LESS_THAN;
    break;
  default:
    // The EQUAL and NOT_EQUAL cases have been already dealt with.
    throw std::runtime_error("PPL internal error");
  }

  // Check whether the preimage of this affine relation can be easily
  // computed as the image of its inverse relation.
  const Coefficient& var_coefficient = expr.coefficient(var);
  if (var_coefficient != 0) {
    Linear_Expression inverse_expr
      = expr - (denominator + var_coefficient) * var;
    PPL_DIRTY_TEMP_COEFFICIENT(inverse_denominator);
    neg_assign(inverse_denominator, var_coefficient);
    Relation_Symbol inverse_relsym
      = (sgn(denominator) == sgn(inverse_denominator))
      ? relsym : reversed_relsym;
    generalized_affine_image(var, inverse_relsym, inverse_expr,
			     inverse_denominator);
    return;
  }

  // Here `var_coefficient == 0', so that the preimage cannot
  // be easily computed by inverting the affine relation.
  // Shrink the box by adding the constraint induced
  // by the affine relation.
  // First, compute the maximum and minimum value reached by
  // `denominator*var' on the box as we need to use non-relational
  // expressions.
  PPL_DIRTY_TEMP(Coefficient, max_num);
  PPL_DIRTY_TEMP(Coefficient, max_den);
  bool max_included;
  bool bound_above = maximize(denominator*var, max_num, max_den, max_included);
  PPL_DIRTY_TEMP(Coefficient, min_num);
  PPL_DIRTY_TEMP(Coefficient, min_den);
  bool min_included;
  bool bound_below = minimize(denominator*var, min_num, min_den, min_included);
  // Use the correct relation symbol
  const Relation_Symbol corrected_relsym
    = (denominator > 0) ? relsym : reversed_relsym;
  // Revise the expression to take into account the denominator of the
  // maximum/minimim value for `var'.
  PPL_DIRTY_TEMP(Linear_Expression, revised_expr);
  dimension_type dim = space_dim;
  PPL_DIRTY_TEMP_COEFFICIENT(d);
  if (corrected_relsym == LESS_THAN || corrected_relsym == LESS_OR_EQUAL) {
    if (bound_below) {
      for ( ; dim > 0; dim--) {
        d = min_den * expr.coefficient(Variable(dim - 1));
        revised_expr += d * Variable(dim - 1);
      }
    }
  }
  else {
    if (bound_above) {
      for ( ; dim > 0; dim--) {
        d = max_den * expr.coefficient(Variable(dim - 1));
        revised_expr += d * Variable(dim - 1);
      }
    }
  }

  switch (corrected_relsym) {
  case LESS_THAN:
    if (bound_below)
      refine_with_constraint(min_num < revised_expr);
    break;
  case LESS_OR_EQUAL:
    if (bound_below)
      (min_included)
        ? refine_with_constraint(min_num <= revised_expr)
        : refine_with_constraint(min_num < revised_expr);
    break;
  case GREATER_OR_EQUAL:
    if (bound_above)
      (max_included)
        ? refine_with_constraint(max_num >= revised_expr)
        : refine_with_constraint(max_num > revised_expr);
    break;
  case GREATER_THAN:
    if (bound_above)
      refine_with_constraint(max_num > revised_expr);
    break;
  default:
    // The EQUAL and NOT_EQUAL cases have been already dealt with.
    throw std::runtime_error("PPL internal error");
  }
  // If the shrunk box is empty, its preimage is empty too.
  if (is_empty())
    return;
  ITV& seq_v = seq[var.id()];
  seq_v.lower_set(UNBOUNDED);
  seq_v.upper_set(UNBOUNDED);
  assert(OK());
}

template <typename ITV>
void
Box<ITV>
::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'.
  dimension_type lhs_space_dim = lhs.space_dimension();
  const dimension_type space_dim = 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);

  // The relation symbol cannot be a disequality.
  if (relsym == NOT_EQUAL)
    throw_generic("generalized_affine_image(e1, r, e2)",
                  "r is the disequality relation symbol");

  // Any image of an empty box is empty.
  if (marked_empty())
    return;

  // Compute the maximum and minimum value reached by the rhs on the box.
  PPL_DIRTY_TEMP(Coefficient, max_num);
  PPL_DIRTY_TEMP(Coefficient, max_den);
  bool max_included;
  bool max_rhs = maximize(rhs, max_num, max_den, max_included);
  PPL_DIRTY_TEMP(Coefficient, min_num);
  PPL_DIRTY_TEMP(Coefficient, min_den);
  bool min_included;
  bool min_rhs = minimize(rhs, min_num, min_den, min_included);

  // Check whether there is 0, 1 or more than one variable in the lhs
  // and record the variable with the highest dimension; set the box
  // intervals to be unbounded for all other dimensions with non-zero
  // coefficients in the lhs.
  bool has_var = false;
  bool has_more_than_one_var = false;
  // Initialization is just to avoid an annoying warning.
  dimension_type has_var_id = 0;
  for ( ; lhs_space_dim > 0; --lhs_space_dim)
    if (lhs.coefficient(Variable(lhs_space_dim - 1)) != 0) {
      if (has_var) {
        ITV& seq_i = seq[lhs_space_dim - 1];
        seq_i.lower_set(UNBOUNDED);
        seq_i.upper_set(UNBOUNDED);
        has_more_than_one_var = true;
      }
      else {
        has_var = true;
        has_var_id = lhs_space_dim - 1;
      }
    }

  if (has_more_than_one_var) {
    // There is more than one dimension with non-zero coefficient, so
    // we cannot have any information about the dimensions in the lhs.
    // Since all but the highest dimension with non-zero coefficient
    // in the lhs have been set unbounded, it remains to set the
    // highest dimension in the lhs unbounded.
    ITV& seq_var = seq[has_var_id];
    seq_var.lower_set(UNBOUNDED);
    seq_var.upper_set(UNBOUNDED);
    assert(OK());
    return;
  }

  if (has_var) {
    // There is exactly one dimension with non-zero coefficient.
    ITV& seq_var = seq[has_var_id];

    // Compute the new bounds for this dimension defined by the rhs
    // expression.
    const Coefficient& inhomo = lhs.inhomogeneous_term();
    const Coefficient& coeff = lhs.coefficient(Variable(has_var_id));
    PPL_DIRTY_TEMP0(mpq_class, q_max);
    PPL_DIRTY_TEMP0(mpq_class, q_min);
    if (max_rhs) {
      max_num -= inhomo * max_den;
      max_den *= coeff;
      assign_r(q_max.get_num(), max_num, ROUND_NOT_NEEDED);
      assign_r(q_max.get_den(), max_den, ROUND_NOT_NEEDED);
      q_max.canonicalize();
    }
    if (min_rhs) {
      min_num -= inhomo * min_den;
      min_den *= coeff;
      assign_r(q_min.get_num(), min_num, ROUND_NOT_NEEDED);
      assign_r(q_min.get_den(), min_den, ROUND_NOT_NEEDED);
      q_min.canonicalize();
    }

    // The choice as to which bounds should be set depends on the sign
    // of the coefficient of the dimension `has_var_id' in the lhs.
    if (coeff > 0)
      // The coefficient of the dimension in the lhs is +ve.
      switch (relsym) {
      case LESS_OR_EQUAL:
        seq_var.lower_set(UNBOUNDED);
        max_rhs
          ? seq_var.upper_set(q_max, !max_included)
          : seq_var.upper_set(UNBOUNDED);
        break;
      case LESS_THAN:
        seq_var.lower_set(UNBOUNDED);
        max_rhs
          ? seq_var.upper_set(q_max, true)
          : seq_var.upper_set(UNBOUNDED);
        break;
      case EQUAL:
        max_rhs
          ? seq_var.upper_set(q_max, !max_included)
          : seq_var.upper_set(UNBOUNDED);
          min_rhs
            ? seq_var.lower_set(q_min, !min_included)
            : seq_var.lower_set(UNBOUNDED);
          break;
      case GREATER_OR_EQUAL:
        seq_var.upper_set(UNBOUNDED);
        min_rhs
          ? seq_var.lower_set(q_min, !min_included)
          : seq_var.lower_set(UNBOUNDED);
        break;
      case GREATER_THAN:
        seq_var.upper_set(UNBOUNDED);
        min_rhs
          ? seq_var.lower_set(q_min, true)
          : seq_var.lower_set(UNBOUNDED);
        break;
      default:
        // The NOT_EQUAL case has been already dealt with.
        throw std::runtime_error("PPL internal error");
      }
    else
      // The coefficient of the dimension in the lhs is -ve.
      switch (relsym) {
      case GREATER_OR_EQUAL:
        seq_var.lower_set(UNBOUNDED);
        min_rhs
          ? seq_var.upper_set(q_min, !min_included)
          : seq_var.upper_set(UNBOUNDED);
        break;
      case GREATER_THAN:
        seq_var.lower_set(UNBOUNDED);
        min_rhs
          ? seq_var.upper_set(q_min, true)
          : seq_var.upper_set(UNBOUNDED);
        break;
      case EQUAL:
        max_rhs
          ? seq_var.lower_set(q_max, !max_included)
          : seq_var.lower_set(UNBOUNDED);
          min_rhs
            ? seq_var.upper_set(q_min, !min_included)
            : seq_var.upper_set(UNBOUNDED);
          break;
      case LESS_OR_EQUAL:
        seq_var.upper_set(UNBOUNDED);
        max_rhs
          ? seq_var.lower_set(q_max, !max_included)
          : seq_var.lower_set(UNBOUNDED);
        break;
      case LESS_THAN:
        seq_var.upper_set(UNBOUNDED);
        max_rhs
          ? seq_var.lower_set(q_max, true)
          : seq_var.lower_set(UNBOUNDED);
        break;
      default:
        // The NOT_EQUAL case has been already dealt with.
        throw std::runtime_error("PPL internal error");
      }
  }

  else {
    // The lhs is a constant value, so we just need to add the
    // appropriate constraint.
    const Coefficient& inhomo = lhs.inhomogeneous_term();
    switch (relsym) {
    case LESS_THAN:
      refine_with_constraint(inhomo < rhs);
      break;
    case LESS_OR_EQUAL:
      refine_with_constraint(inhomo <= rhs);
      break;
    case EQUAL:
      refine_with_constraint(inhomo == rhs);
      break;
    case GREATER_OR_EQUAL:
      refine_with_constraint(inhomo >= rhs);
      break;
    case GREATER_THAN:
      refine_with_constraint(inhomo > rhs);
      break;
    default:
      // The NOT_EQUAL case has been already dealt with.
      throw std::runtime_error("PPL internal error");
    }
  }
  assert(OK());
}

template <typename ITV>
void
Box<ITV>::generalized_affine_preimage(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'.
  dimension_type lhs_space_dim = lhs.space_dimension();
  const dimension_type space_dim = 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);

  // The relation symbol cannot be a disequality.
  if (relsym == NOT_EQUAL)
    throw_generic("generalized_affine_image(e1, r, e2)",
                  "r is the disequality relation symbol");

  // Any image of an empty box is empty.
  if (marked_empty())
    return;

  // For any dimension occurring in the lhs, swap and change the sign
  // of this component for the rhs and lhs.  Then use these in a call
  // to generalized_affine_image/3.
  Linear_Expression revised_lhs = lhs;
  Linear_Expression revised_rhs = rhs;
  for (dimension_type d = lhs_space_dim; d-- > 0; ) {
    const Variable& var = Variable(d);
    if (lhs.coefficient(var) != 0) {
      PPL_DIRTY_TEMP(Coefficient, temp);
      temp = rhs.coefficient(var) + lhs.coefficient(var);
      revised_rhs -= temp * var;
      revised_lhs -= temp * var;
    }
  }
  generalized_affine_image(revised_lhs, relsym, revised_rhs);
  assert(OK());
}

template <typename ITV>
template <typename Iterator>
void
Box<ITV>::CC76_widening_assign(const Box& y, Iterator first, Iterator last) {
  if (y.is_empty())
    return;

  for (dimension_type i = seq.size(); i-- > 0; )
    seq[i].CC76_widening_assign(y.seq[i], first, last);

  assert(OK());
}

template <typename ITV>
void
Box<ITV>::CC76_widening_assign(const Box& y, unsigned* tp) {
  static typename ITV::boundary_type stop_points[] = {
    typename ITV::boundary_type(-2),
    typename ITV::boundary_type(-1),
    typename ITV::boundary_type(0),
    typename ITV::boundary_type(1),
    typename ITV::boundary_type(2)
  };

  Box& x = *this;
  // If there are tokens available, work on a temporary copy.
  if (tp != 0 && *tp > 0) {
    Box<ITV> x_tmp(x);
    x_tmp.CC76_widening_assign(y, 0);
    // If the widening was not precise, use one of the available tokens.
    if (!x.contains(x_tmp))
      --(*tp);
    return;
  }
  x.CC76_widening_assign(y,
			 stop_points,
			 stop_points
			 + sizeof(stop_points)/sizeof(stop_points[0]));
}

template <typename ITV>
void
Box<ITV>::get_limiting_box(const Constraint_System& cs,
                           Box& limiting_box) const {
  const dimension_type cs_space_dim = cs.space_dimension();
  // Private method: the caller has to ensure the following.
  assert(cs_space_dim <= space_dimension());

  for (Constraint_System::const_iterator cs_i = cs.begin(),
         cs_end = cs.end(); cs_i != cs_end; ++cs_i) {
    const Constraint& c = *cs_i;
    dimension_type c_num_vars = 0;
    dimension_type c_only_var = 0;
    // Constraints that are not interval constraints are ignored.
    if (!extract_interval_constraint(c, cs_space_dim, c_num_vars, c_only_var))
      continue;
    // Trivial constraints are ignored.
    if (c_num_vars != 0) {
      // c is a non-trivial interval constraint.
      // add interval constraint to limiting box
      const Coefficient& n = c.inhomogeneous_term();
      const Coefficient& d = c.coefficient(Variable(c_only_var));
      if (interval_relation(seq[c_only_var], c.type(), n, d)
          == Poly_Con_Relation::is_included())
        limiting_box.add_interval_constraint_no_check(c_only_var, c.type(),
                                                      n, d);
    }
  }
}

template <typename ITV>
void
Box<ITV>::limited_CC76_extrapolation_assign(const Box& y,
                                            const Constraint_System& cs,
                                            unsigned* tp) {
  Box& x = *this;
  const dimension_type space_dim = x.space_dimension();

  // Dimension-compatibility check.
  if (space_dim != y.space_dimension())
    throw_dimension_incompatible("limited_CC76_extrapolation_assign(y, cs)",
                                 y);
  // `cs' must be dimension-compatible with the two boxes.
  const dimension_type cs_space_dim = cs.space_dimension();
  if (space_dim < cs_space_dim)
    throw_constraint_incompatible("limited_CC76_extrapolation_assign(y, cs)");

  // The limited CC76-extrapolation between two boxes in a
  // zero-dimensional space is also a zero-dimensional box
  if (space_dim == 0)
    return;

#ifndef NDEBUG
  {
    // We assume that `y' is contained in or equal to `*this'.
    const Box x_copy = *this;
    const Box 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;

  // Build a limiting box using all the constraints in cs
  // that are satisfied by *this.
  Box limiting_box(space_dim, UNIVERSE);
  get_limiting_box(cs, limiting_box);

  x.CC76_widening_assign(y, tp);

  // Intersect the widened box with the limiting box.
  intersection_assign(limiting_box);
}

template <typename ITV>
void
Box<ITV>::CC76_narrowing_assign(const Box& 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 Box x_copy = *this;
    const Box y_copy = y;
    assert(y_copy.contains(x_copy));
  }
#endif

  // If both boxes are zero-dimensional,
  // since `y' contains `*this', we simply return `*this'.
  if (space_dim == 0)
    return;

  // If `y' is empty, since `y' contains `this', `*this' is empty too.
  if (y.is_empty())
    return;
  // If `*this' is empty, we return.
  if (is_empty())
    return;

  // Replace each constraint in `*this' by the corresponding constraint
  // in `y' if the corresponding inhomogeneous terms are both finite.
  for (dimension_type i = space_dim; i-- > 0; ) {
    ITV& x_i = seq[i];
    const ITV& y_i = y.seq[i];
    if (!x_i.lower_is_unbounded()
	&& !y_i.lower_is_unbounded()
	&& x_i.lower() != y_i.lower())
      x_i.lower() = y_i.lower();
    if (!x_i.upper_is_unbounded()
	&& !y_i.upper_is_unbounded()
	&& x_i.upper() != y_i.upper())
      x_i.upper() = y_i.upper();
  }
  assert(OK());
}

template <typename ITV>
Constraint_System
Box<ITV>::constraints() const {
  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);

    for (dimension_type k = 0; k < space_dim; ++k) {
      bool closed = false;
      PPL_DIRTY_TEMP(Coefficient, n);
      PPL_DIRTY_TEMP(Coefficient, d);
      if (get_lower_bound(k, closed, n, d)) {
	if (closed)
	  cs.insert(d*Variable(k) >= n);
	else
	  cs.insert(d*Variable(k) > n);
      }
      if (get_upper_bound(k, closed, n, d)) {
	if (closed)
	  cs.insert(d*Variable(k) <= n);
	else
	  cs.insert(d*Variable(k) < n);
      }
    }
  }
  return cs;
}

template <typename ITV>
Constraint_System
Box<ITV>::minimized_constraints() const {
  Constraint_System cs;
  const dimension_type space_dim = space_dimension();
  if (space_dim == 0) {
    if (marked_empty())
      cs = Constraint_System::zero_dim_empty();
  }
  // Make sure emptiness is detected.
  else if (is_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);

    for (dimension_type k = 0; k < space_dim; ++k) {
      bool closed = false;
      PPL_DIRTY_TEMP(Coefficient, n);
      PPL_DIRTY_TEMP(Coefficient, d);
      if (get_lower_bound(k, closed, n, d)) {
	if (closed)
	  // Make sure equality constraints are detected.
	  if (seq[k].is_singleton()) {
	    cs.insert(d*Variable(k) == n);
	    continue;
	  }
	  else
	    cs.insert(d*Variable(k) >= n);
	else
	  cs.insert(d*Variable(k) > n);
      }
      if (get_upper_bound(k, closed, n, d)) {
	if (closed)
	  cs.insert(d*Variable(k) <= n);
	else
	  cs.insert(d*Variable(k) < n);
      }
    }
  }
  return cs;
}

template <typename ITV>
Congruence_System
Box<ITV>::congruences() const {
  Congruence_System cgs;
  const dimension_type space_dim = space_dimension();
  if (space_dim == 0) {
    if (marked_empty())
      cgs = Congruence_System::zero_dim_empty();
  }
  // Make sure emptiness is detected.
  else if (is_empty())
    cgs.insert((0*Variable(space_dim-1) %= -1) / 0);
  else {
    // KLUDGE: in the future `cgs' will be constructed of the right dimension.
    // For the time being, we force the dimension with the following line.
    cgs.insert(0*Variable(space_dim-1) %= 0);

    for (dimension_type k = 0; k < space_dim; ++k) {
      bool closed = false;
      PPL_DIRTY_TEMP(Coefficient, n);
      PPL_DIRTY_TEMP(Coefficient, d);
      if (get_lower_bound(k, closed, n, d) && closed)
	  // Make sure equality congruences are detected.
	  if (seq[k].is_singleton())
	    cgs.insert((d*Variable(k) %= n) / 0);
    }
  }
  return cgs;
}

template <typename ITV>
memory_size_type
Box<ITV>::external_memory_in_bytes() const {
  memory_size_type n = seq.capacity() * sizeof(ITV);
  for (dimension_type k = seq.size(); k-- > 0; )
    n += seq[k].external_memory_in_bytes();
  return n;
}

/*! \relates Parma_Polyhedra_Library::Box */
template <typename ITV>
std::ostream&
IO_Operators::operator<<(std::ostream& s, const Box<ITV>& box) {
  if (box.is_empty())
    s << "false";
  else if (box.is_universe())
    s << "true";
  else
    for (dimension_type k = 0,
	   space_dim = box.space_dimension(); k < space_dim; ) {
      s << Variable(k) << " in " << box[k];
      ++k;
      if (k < space_dim)
	s << ", ";
      else
	break;
    }
  return s;
}

template <typename ITV>
void
Box<ITV>::ascii_dump(std::ostream& s) const {
  const char separator = ' ';
  status.ascii_dump(s);
  const dimension_type space_dim = space_dimension();
  s << "space_dim" << separator << space_dim;
  s << "\n";
  for (dimension_type i = 0; i < space_dim;  ++i)
    seq[i].ascii_dump(s);
}

PPL_OUTPUT_TEMPLATE_DEFINITIONS(ITV, Box<ITV>)

template <typename ITV>
bool
Box<ITV>::ascii_load(std::istream& s) {
  if (!status.ascii_load(s))
    return false;

  std::string str;
  dimension_type space_dim;
  if (!(s >> str) || str != "space_dim")
    return false;
  if (!(s >> space_dim))
    return false;

  seq.clear();
  ITV seq_i;
  for (dimension_type i = 0; i < space_dim;  ++i) {
    if (seq_i.ascii_load(s))
      seq.push_back(seq_i);
    else
      return false;
  }

  // Check invariants.
  assert(OK());
  return true;
}

template <typename ITV>
void
Box<ITV>::throw_dimension_incompatible(const char* method,
                                       const Box& y) const {
  std::ostringstream s;
  s << "PPL::Box::" << method << ":" << std::endl
    << "this->space_dimension() == " << this->space_dimension()
    << ", y->space_dimension() == " << y.space_dimension() << ".";
  throw std::invalid_argument(s.str());
}

template <typename ITV>
void
Box<ITV>
::throw_dimension_incompatible(const char* method,
			       dimension_type required_dim) const {
  std::ostringstream s;
  s << "PPL::Box::" << method << ":" << std::endl
    << "this->space_dimension() == " << space_dimension()
    << ", required dimension == " << required_dim << ".";
  throw std::invalid_argument(s.str());
}

template <typename ITV>
void
Box<ITV>::throw_dimension_incompatible(const char* method,
                                       const Constraint& c) const {
  std::ostringstream s;
  s << "PPL::Box::" << method << ":" << std::endl
    << "this->space_dimension() == " << space_dimension()
    << ", c->space_dimension == " << c.space_dimension() << ".";
  throw std::invalid_argument(s.str());
}

template <typename ITV>
void
Box<ITV>::throw_dimension_incompatible(const char* method,
                                       const Congruence& cg) const {
  std::ostringstream s;
  s << "PPL::Box::" << method << ":" << std::endl
    << "this->space_dimension() == " << space_dimension()
    << ", cg->space_dimension == " << cg.space_dimension() << ".";
  throw std::invalid_argument(s.str());
}

template <typename ITV>
void
Box<ITV>::throw_dimension_incompatible(const char* method,
                                       const Constraint_System& cs) const {
  std::ostringstream s;
  s << "PPL::Box::" << method << ":" << std::endl
    << "this->space_dimension() == " << space_dimension()
    << ", cs->space_dimension == " << cs.space_dimension() << ".";
  throw std::invalid_argument(s.str());
}

template <typename ITV>
void
Box<ITV>::throw_dimension_incompatible(const char* method,
                                       const Congruence_System& cgs) const {
  std::ostringstream s;
  s << "PPL::Box::" << method << ":" << std::endl
    << "this->space_dimension() == " << space_dimension()
    << ", cgs->space_dimension == " << cgs.space_dimension() << ".";
  throw std::invalid_argument(s.str());
}

template <typename ITV>
void
Box<ITV>::throw_dimension_incompatible(const char* method,
                                       const Generator& g) const {
  std::ostringstream s;
  s << "PPL::Box::" << method << ":" << std::endl
    << "this->space_dimension() == " << space_dimension()
    << ", g->space_dimension == " << g.space_dimension() << ".";
  throw std::invalid_argument(s.str());
}

template <typename ITV>
void
Box<ITV>::throw_constraint_incompatible(const char* method) {
  std::ostringstream s;
  s << "PPL::Box::" << method << ":" << std::endl
    << "the constraint is incompatible.";
  throw std::invalid_argument(s.str());
}

template <typename ITV>
void
Box<ITV>::throw_expression_too_complex(const char* method,
                                       const Linear_Expression& e) {
  using namespace IO_Operators;
  std::ostringstream s;
  s << "PPL::Box::" << method << ":" << std::endl
    << e << " is too complex.";
  throw std::invalid_argument(s.str());
}

template <typename ITV>
void
Box<ITV>::throw_dimension_incompatible(const char* method,
                                       const char* name_row,
                                       const Linear_Expression& e) const {
  std::ostringstream s;
  s << "PPL::Box::" << method << ":" << std::endl
    << "this->space_dimension() == " << space_dimension()
    << ", " << name_row << "->space_dimension() == "
    << e.space_dimension() << ".";
  throw std::invalid_argument(s.str());
}

template <typename ITV>
void
Box<ITV>::throw_generic(const char* method, const char* reason) {
  std::ostringstream s;
  s << "PPL::Box::" << method << ":" << std::endl
    << reason;
  throw std::invalid_argument(s.str());
}

template <typename ITV>
void
Box<ITV>::throw_space_dimension_overflow(const char* method,
                                         const char* reason) {
  std::ostringstream s;
  s << "PPL::Box::" << method << ":" << std::endl
    << reason;
  throw std::length_error(s.str());
}

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \relates Box */
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename Specialization,
	  typename Temp, typename To, typename ITV>
bool
l_m_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
		    const Box<ITV>& x, const Box<ITV>& 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 boxes 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
      assign_r(r, PLUS_INFINITY, ROUND_NOT_NEEDED);
    return true;
  }

  // The distance computation requires a check for emptiness.
  (void) x.is_empty();
  (void) y.is_empty();
  // If one of two boxes is empty, then they are equal if and only if
  // the other box is empty too.
  if (x.marked_empty() || y.marked_empty()) {
    if (x.marked_empty() == y.marked_empty()) {
      assign_r(r, 0, ROUND_NOT_NEEDED);
      return true;
    }
    else
      goto pinf;
  }

  assign_r(tmp0, 0, ROUND_NOT_NEEDED);
  for (dimension_type i = x_space_dim; i-- > 0; ) {
    const ITV& x_i = x.seq[i];
    const ITV& y_i = y.seq[i];
    // Dealing with the lower bounds.
    if (x_i.lower_is_unbounded()) {
      if (!y_i.lower_is_unbounded())
	goto pinf;
    }
    else if (y_i.lower_is_unbounded())
      goto pinf;
    else {
      const Temp* tmp1p;
      const Temp* tmp2p;
      if (x_i.lower() > y_i.lower()) {
	maybe_assign(tmp1p, tmp1, x_i.lower(), dir);
	maybe_assign(tmp2p, tmp2, y_i.lower(), inverse(dir));
      }
      else {
	maybe_assign(tmp1p, tmp1, y_i.lower(), dir);
	maybe_assign(tmp2p, tmp2, x_i.lower(), inverse(dir));
      }
      sub_assign_r(tmp1, *tmp1p, *tmp2p, dir);
      assert(sgn(tmp1) >= 0);
      Specialization::combine(tmp0, tmp1, dir);
    }
    // Dealing with the lower bounds.
    if (x_i.upper_is_unbounded())
      if (y_i.upper_is_unbounded())
	continue;
      else
	goto pinf;
    else if (y_i.upper_is_unbounded())
      goto pinf;
    else {
      const Temp* tmp1p;
      const Temp* tmp2p;
      if (x_i.upper() > y_i.upper()) {
	maybe_assign(tmp1p, tmp1, x_i.upper(), dir);
	maybe_assign(tmp2p, tmp2, y_i.upper(), inverse(dir));
      }
      else {
	maybe_assign(tmp1p, tmp1, y_i.upper(), dir);
	maybe_assign(tmp2p, tmp2, x_i.upper(), inverse(dir));
      }
      sub_assign_r(tmp1, *tmp1p, *tmp2p, dir);
      assert(sgn(tmp1) >= 0);
      Specialization::combine(tmp0, tmp1, dir);
    }
  }
  Specialization::finalize(tmp0, dir);
  assign_r(r, tmp0, dir);
  return true;

 pinf:
  assign_r(r, PLUS_INFINITY, ROUND_NOT_NEEDED);
  return true;
}

} // namespace Parma_Polyhedra_Library

/* Automatically generated from PPL source file ../src/Box.defs.hh line 2058. */

/* Automatically generated from PPL source file ../src/Rational_Box.hh line 28. */

namespace Parma_Polyhedra_Library {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! A box with rational, possibly open boundaries.
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
typedef Box<Rational_Interval> Rational_Box;

} // namespace Parma_Polyhedra_Library

/* Automatically generated from PPL source file ../src/max_space_dimension.hh line 33. */
#include <algorithm>

namespace Parma_Polyhedra_Library {

//! Returns the maximum space dimension this library can handle.
inline dimension_type
max_space_dimension() {
  // Note: we assume that the powerset and the ask-and-tell construction
  // do not limit the space dimension more than their parameters.
  static bool computed = false;
  static dimension_type d = not_a_dimension();
  if (!computed) {
    d = Variable::max_space_dimension();
    d = std::min(d, C_Polyhedron::max_space_dimension());
    d = std::min(d, NNC_Polyhedron::max_space_dimension());
    d = std::min(d, Grid::max_space_dimension());
    // FIXME: what about all other boxes?
    d = std::min(d, Rational_Box::max_space_dimension());
    d = std::min(d, BD_Shape<int8_t>::max_space_dimension());
    d = std::min(d, BD_Shape<int16_t>::max_space_dimension());
    d = std::min(d, BD_Shape<int32_t>::max_space_dimension());
    d = std::min(d, BD_Shape<int64_t>::max_space_dimension());
    d = std::min(d, BD_Shape<float>::max_space_dimension());
    d = std::min(d, BD_Shape<double>::max_space_dimension());
    d = std::min(d, BD_Shape<long double>::max_space_dimension());
    d = std::min(d, BD_Shape<mpz_class>::max_space_dimension());
    d = std::min(d, BD_Shape<mpq_class>::max_space_dimension());
    d = std::min(d, Octagonal_Shape<int8_t>::max_space_dimension());
    d = std::min(d, Octagonal_Shape<int16_t>::max_space_dimension());
    d = std::min(d, Octagonal_Shape<int32_t>::max_space_dimension());
    d = std::min(d, Octagonal_Shape<int64_t>::max_space_dimension());
    d = std::min(d, Octagonal_Shape<float>::max_space_dimension());
    d = std::min(d, Octagonal_Shape<double>::max_space_dimension());
    d = std::min(d, Octagonal_Shape<long double>::max_space_dimension());
    d = std::min(d, Octagonal_Shape<mpz_class>::max_space_dimension());
    d = std::min(d, Octagonal_Shape<mpq_class>::max_space_dimension());
    computed = true;
  }
  return d;
}

} // 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/Pointset_Powerset.defs.hh line 1. */
/* Pointset_Powerset class declaration.
*/


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


namespace Parma_Polyhedra_Library {

template <typename PH>
class Pointset_Powerset;

} // namespace Parma_Polyhedra_Library

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


/* Automatically generated from PPL source file ../src/Partially_Reduced_Product.defs.hh line 48. */

namespace Parma_Polyhedra_Library {

namespace IO_Operators {

//! Output operator.
/*!
  \relates Parma_Polyhedra_Library::Partially_Reduced_Product
  Writes a textual representation of \p dp on \p s.
*/
template <typename D1, typename D2, typename R>
std::ostream&
operator<<(std::ostream& s, const Partially_Reduced_Product<D1, D2, R>& dp);

} // namespace IO_Operators

/*! \brief
  Returns <CODE>true</CODE> if and only if the components of \p x and \p y
  are pairwise equal.

  \relates Partially_Reduced_Product
  Note that \p x and \p y may be dimension-incompatible: in
  those cases, the value <CODE>false</CODE> is returned.
*/
template <typename D1, typename D2, typename R>
bool operator==(const Partially_Reduced_Product<D1, D2, R>& x,
		const Partially_Reduced_Product<D1, D2, R>& y);

/*! \brief
  Returns <CODE>true</CODE> if and only if the components of \p x and \p y
  are not pairwise equal.

  \relates Partially_Reduced_Product
  Note that \p x and \p y may be dimension-incompatible: in
  those cases, the value <CODE>true</CODE> is returned.
*/
template <typename D1, typename D2, typename R>
bool operator!=(const Partially_Reduced_Product<D1, D2, R>& x,
		const Partially_Reduced_Product<D1, D2, R>& y);

} // namespace Parma_Polyhedra_Library


/*! \brief
  This class provides the reduction method for the Smash_Product
  domain.

  \ingroup PPL_CXX_interface
  The reduction classes are used to instantiate the Partially_Reduced_Product
  domain. This class propagates emptiness between its components.
*/
template <typename D1, typename D2>
class Parma_Polyhedra_Library::Smash_Reduction {
public:
  //! Default constructor.
  Smash_Reduction();

  /*! \brief
    The smash reduction operator for propagating emptiness between the
    domain elements \p d1 and \p d2.

    If either of the the domain elements \p d1 or \p d2 is empty
    then the other is also set empty.

    \param d1
    A pointset domain element;

    \param d2
    A pointset domain element;
  */
  void product_reduce(D1& d1, D2& d2);

  //! Destructor.
  ~Smash_Reduction();
};

/*! \brief
  This class provides the reduction method for the Constraints_Product
  domain.

  \ingroup PPL_CXX_interface
  The reduction classes are used to instantiate the Partially_Reduced_Product
  domain. This class adds the constraints defining each of the component
  domains to the other component.
*/
template <typename D1, typename D2>
class Parma_Polyhedra_Library::Constraints_Reduction {
public:
  //! Default constructor.
  Constraints_Reduction();

  /*! \brief
    The constraints reduction operator for sharing constraints between the
    domains.

    The minimized constraint system defining the domain element \p d1
    is added to \p d2 and the minimized constraint system  defining \p d2
    is added to \p d1.
    In each case, the donor domain must provide a constraint system
    in minimal form; this must define a polyhedron in which the
    donor element is contained.
    The recipient domain selects a subset of these constraints
    that it can add to the recipient element.
    For example: if the domain \p D1 is the Grid domain and \p D2
    the NNC Polyhedron domain, then only the equality constraints are copied
    from \p d1 to \p d2 and from \p d2 to \p d1.

    \param d1
    A pointset domain element;

    \param d2
    A pointset domain element;
  */
  void product_reduce(D1& d1, D2& d2);

  //! Destructor.
  ~Constraints_Reduction();
};

/*! \brief
  This class provides the reduction method for the Direct_Product domain.

  \ingroup PPL_CXX_interface
  The reduction classes are used to instantiate the Partially_Reduced_Product
  domain template parameter \p R. This class does no reduction at all.
*/
template <typename D1, typename D2>
class Parma_Polyhedra_Library::No_Reduction {
public:
  //! Default constructor.
  No_Reduction();

  /*! \brief
    The null reduction operator.

    The parameters \p d1 and \p d2 are ignored.
  */
  void product_reduce(D1& d1, D2& d2);

  //! Destructor.
  ~No_Reduction();
};

//! The partially reduced product of two abstractions.
/*! \ingroup PPL_CXX_interface

  \warning
  At present, the supported instantiations for the
  two domain templates \p D1 and \p D2 are the simple pointset domains:
  <CODE>C_Polyhedron</CODE>,
  <CODE>NNC_Polyhedron</CODE>,
  <CODE>Grid</CODE>,
  <CODE>Octagonal_Shape<T></CODE>,
  <CODE>BD_Shape<T></CODE>,
  <CODE>Box<T></CODE>.

  An object of the class <CODE>Partially_Reduced_Product<D1, D2, R></CODE>
  represents the (partially reduced) product of two pointset domains \p D1
  and \p D2 where the form of any reduction is defined by the
  reduction class \p R.

  Suppose \f$D_1\f$ and \f$D_2\f$ are two abstract domains
  with concretization functions:
  \f$\fund{\gamma_1}{D_1}{\Rset^n}\f$ and
  \f$\fund{\gamma_2}{D_2}{\Rset^n}\f$, respectively.

  The partially reduced product \f$D = D_1 \times D_2\f$,
  for any reduction class \p R, has a concretization
  \f$\fund{\gamma}{D}{\Rset^n}\f$
  where, if \f$d = (d_1, d_2) \in D\f$
  \f[
    \gamma(d) = \gamma_1(d_1) \inters \gamma_2(d_2).
  \f]

  The operations are defined to be the result of applying the corresponding
  operations on each of the components provided the product is already reduced
  by the reduction method defined by \p R.
  In particular, if \p R is the <CODE>No_Reduction<D1, D2></CODE> class,
  then the class <CODE>Partially_Reduced_Product<D1, D2, R></CODE> domain
  is the direct product as defined in \ref CC79 "[CC79]".

  How the results on the components are interpreted and
  combined depend on the specific test.
  For example, the test for emptiness will first make sure
  the product is reduced (using the reduction method provided by \p R
  if it is not already known to be reduced) and then test if either component
  is empty; thus, if \p R defines no reduction between its components and
  \f$d = (G, P) \in (\Gset \times \Pset)\f$
  is a direct product in one dimension where \f$G\f$ denotes the set of
  numbers that are integral multiples of 3 while \f$P\f$ denotes the
  set of numbers between 1 and 2, then an operation that tests for
  emptiness should return false.
  However, the test for the universe returns true if and only if the
  test <CODE>is_universe()</CODE> on both components returns true.

  \par
  In all the examples it is assumed that the template \c R is the
  <CODE>No_Reduction<D1, D2></CODE> class and that variables
  \c x and \c y are defined (where they are used) as follows:
  \code
  Variable x(0);
  Variable y(1);
  \endcode

  \par Example 1
  The following code builds a direct product of a Grid and NNC Polyhedron,
  corresponding to the positive 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);
  Partially_Reduced_Product<Grid, NNC_Polyhedron, No_Reduction<D1, D2> >
    dp(cgs);
  dp.add_constraint(x >= 0);
  dp.add_constraint(y >= 0);
  \endcode

  \par Example 2
  The following code builds the same product
  in \f$\Rset^2\f$:
  \code
  Partially_Reduced_Product<Grid, NNC_Polyhedron, No_Reduction<D1, D2> > dp(2);
  dp.add_constraint(x >= 0);
  dp.add_constraint(y >= 0);
  dp.add_congruence((x %= 0) / 2);
  dp.add_congruence((y %= 0) / 2);
  \endcode

  \par Example 3
  The following code will write "dp is empty":
  \code
  Partially_Reduced_Product<Grid, NNC_Polyhedron, No_Reduction<D1, D2> > dp(1);
  dp.add_congruence((x %= 0) / 2);
  dp.add_congruence((x %= 1) / 2);
  if (dp.is_empty())
    cout << "dp is empty." << endl;
  else
    cout << "dp is not empty." << endl;
  \endcode

  \par Example 4
  The following code will write "dp is not empty":
  \code
  Partially_Reduced_Product<Grid, NNC_Polyhedron, No_Reduction<D1, D2> > dp(1);
  dp.add_congruence((x %= 0) / 2);
  dp.add_constraint(x >= 1);
  dp.add_constraint(x <= 1);
  if (dp.is_empty())
    cout << "dp is empty." << endl;
  else
    cout << "dp is not empty." << endl;
  \endcode
*/

template <typename D1, typename D2, typename R>
class Parma_Polyhedra_Library::Partially_Reduced_Product {
public:
  /*! \brief
    Returns the maximum space dimension this product
    can handle.
  */
  static dimension_type max_space_dimension();

  //! Builds an object having the specified properties.
  /*!
    \param num_dimensions
    The number of dimensions of the vector space enclosing the pair;

    \param kind
    Specifies whether a universe or an empty pair has to be built.

    \exception std::length_error
    Thrown if \p num_dimensions exceeds the maximum allowed space
    dimension.
  */
  explicit Partially_Reduced_Product(dimension_type num_dimensions = 0,
				     Degenerate_Element kind = UNIVERSE);

  //! Builds a pair, copying a system of congruences.
  /*!
    The pair inherits the space dimension of the congruence system.

    \param cgs
    The system of congruences to be approximated by the pair.

    \exception std::invalid_argument
    Thrown if the system of congruences is imcompatible with one of the
    components.

    \exception std::length_error
    Thrown if the space dimension of \p cgs exceeds the maximum allowed
    space dimension.
  */
  explicit Partially_Reduced_Product(const Congruence_System& cgs);

  //! Builds a pair, recycling a system of congruences.
  /*!
    The pair inherits the space dimension of the congruence system.

    \param cgs
    The system of congruences to be approximates by the pair.
    Its data-structures may be recycled to build the pair.

    \exception std::invalid_argument
    Thrown if the system of congruences is imcompatible with one of the
    components.

    \exception std::length_error
    Thrown if the space dimension of \p cgs exceeds the maximum allowed
    space dimension.
  */
  explicit Partially_Reduced_Product(Congruence_System& cgs);

  //! Builds a pair, copying a system of constraints.
  /*!
    The pair inherits the space dimension of the constraint system.

    \param cs
    The system of constraints to be approximated by the pair.

    \exception std::invalid_argument
    Thrown if the system of constraints is imcompatible with one of the
    components.

    \exception std::length_error
    Thrown if the space dimension of \p cs exceeds the maximum allowed
    space dimension.
  */
  explicit Partially_Reduced_Product(const Constraint_System& cs);

  //! Builds a pair, recycling a system of constraints.
  /*!
    The pair inherits the space dimension of the constraint system.

    \param cs
    The system of constraints to be approximated by the pair.

    \exception std::invalid_argument
    Thrown if the system of constraints is imcompatible with one of the
    components.

    \exception std::length_error
    Thrown if the space dimension of \p cs exceeds the maximum allowed
    space dimension.
  */
  explicit Partially_Reduced_Product(Constraint_System& cs);

  //! Builds a product, from a C polyhedron.
  /*!
    Builds a product 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 built product is the
    smallest one containing \p ph.
    The product inherits the space dimension of the polyhedron.

    \param ph
    The polyhedron to be approximated by the product.

    \param complexity
    The complexity that will not be exceeded.

    \exception std::length_error
    Thrown if the space dimension of \p ph exceeds the maximum allowed
    space dimension.
  */
  explicit
  Partially_Reduced_Product(const C_Polyhedron& ph,
                            Complexity_Class complexity = ANY_COMPLEXITY);

  //! Builds a product, from an NNC polyhedron.
  /*!
    Builds a product 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 built product is the
    smallest one containing \p ph.
    The product inherits the space dimension of the polyhedron.

    \param ph
    The polyhedron to be approximated by the product.

    \param complexity
    The complexity that will not be exceeded.

    \exception std::length_error
    Thrown if the space dimension of \p ph exceeds the maximum allowed
    space dimension.
  */
  explicit
  Partially_Reduced_Product(const NNC_Polyhedron& ph,
                            Complexity_Class complexity = ANY_COMPLEXITY);

  //! Builds a product, from a grid.
  /*!
    Builds a product containing \p gr.
    The product inherits the space dimension of the grid.

    \param gr
    The grid to be approximated by the product.

    \param complexity
    The complexity is ignored.

    \exception std::length_error
    Thrown if the space dimension of \p gr exceeds the maximum allowed
    space dimension.
  */
  explicit
  Partially_Reduced_Product(const Grid& gr,
                            Complexity_Class complexity = ANY_COMPLEXITY);

  //! Builds a product out of a box.
  /*!
    Builds a product containing \p box.
    The product inherits the space dimension of the box.

    \param box
    The box representing the pair to be built.

    \param complexity
    The complexity is ignored.

    \exception std::length_error
    Thrown if the space dimension of \p box exceeds the maximum allowed
    space dimension.
  */
  template <typename Interval>
  Partially_Reduced_Product(const Box<Interval>& box,
                            Complexity_Class complexity = ANY_COMPLEXITY);

  //! Builds a product out of a BD shape.
  /*!
    Builds a product containing \p bd.
    The product inherits the space dimension of the BD shape.

    \param bd
    The BD shape representing the product to be built.

    \param complexity
    The complexity is ignored.

    \exception std::length_error
    Thrown if the space dimension of \p bd exceeds the maximum allowed
    space dimension.
  */
  template <typename U>
  Partially_Reduced_Product(const BD_Shape<U>& bd,
                            Complexity_Class complexity = ANY_COMPLEXITY);

  //! Builds a product out of an octagonal shape.
  /*!
    Builds a product containing \p os.
    The product inherits the space dimension of the octagonal shape.

    \param os
    The octagonal shape representing the product to be built.

    \param complexity
    The complexity is ignored.

    \exception std::length_error
    Thrown if the space dimension of \p os exceeds the maximum allowed
    space dimension.
  */
  template <typename U>
  Partially_Reduced_Product(const Octagonal_Shape<U>& os,
                            Complexity_Class complexity = ANY_COMPLEXITY);

  //! Ordinary copy-constructor.
  Partially_Reduced_Product(const Partially_Reduced_Product& y,
                            Complexity_Class complexity = ANY_COMPLEXITY);

  //! Builds a conservative, upward approximation of \p y.
  /*!
    Builds a product containing \p y using algorithms whose
    complexity does not exceed the one specified by \p complexity.
    If \p complexity is \p ANY_COMPLEXITY, then the built product is the
    smallest one containing \p y.
    The product inherits the space dimension of y.

    \param y
    The product to be approximated.

    \param complexity
    The complexity that will not be exceeded.

    \exception std::length_error
    Thrown if the space dimension of \p y exceeds the maximum allowed
    space dimension.

    The built product is independent of the order of the components of \p y.
  */
  template <typename E1, typename E2, typename S>
  explicit
  Partially_Reduced_Product(const Partially_Reduced_Product<E1, E2, S>& y,
                            Complexity_Class complexity = ANY_COMPLEXITY);

  /*! \brief
    The assignment operator.  (\p *this and \p y can be
    dimension-incompatible.)
  */
  Partially_Reduced_Product& operator=(const Partially_Reduced_Product& y);

  //! \name Member Functions that Do Not Modify the Partially_Reduced_Product
  //@{

  //! Returns the dimension of the vector space enclosing \p *this.
  dimension_type space_dimension() const;

  /*! \brief
    Returns the minimum \ref Affine_Independence_and_Affine_Dimension
    "affine dimension"
    (see also \ref Grid_Affine_Dimension "grid affine dimension")
    of the components of \p *this.
  */
  dimension_type affine_dimension() const;

  //! Returns a constant reference to the first of the pair.
  const D1& domain1() const;

  //! Returns a constant reference to the second of the pair.
  const D2& domain2() const;

  //! Returns a system of constraints which approximates \p *this.
  Constraint_System constraints() const;

  /*! \brief
    Returns a system of constraints which approximates \p *this, in
    reduced form.
  */
  Constraint_System minimized_constraints() const;

  //! Returns a system of congruences which approximates \p *this.
  Congruence_System congruences() const;

  /*! \brief
    Returns a system of congruences which approximates \p *this, in
    reduced form.
  */
  Congruence_System minimized_congruences() const;

  //! Returns the relations holding between \p *this and \p c.
  /*
    \exception std::invalid_argument
    Thrown if \p *this and congruence \p cg are dimension-incompatible.

    Returns the Poly_Con_Relation \p r for \p *this:
    suppose the first component returns \p r1 and the second \p r2,
    then \p r implies <CODE>is_included()</CODE>
    if and only if one or both of \p r1 and \p r2 imply
    <CODE>is_included()</CODE>;
    \p r implies <CODE>saturates()</CODE>
    if and only if one or both of \p r1 and \p r2 imply
    <CODE>saturates()</CODE>;
    \p r implies <CODE>is_disjoint()</CODE>
    if and only if one or both of \p r1 and \p r2 imply
    <CODE>is_disjoint()</CODE>;
    and \p r implies <CODE>nothing()</CODE>
    if and only if both \p r1 and \p r2 imply
    <CODE>strictly_intersects()</CODE>.
  */
  Poly_Con_Relation relation_with(const Constraint& c) 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.
  */
  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.

    Returns the Poly_Gen_Relation \p r for \p *this:
    suppose the first component returns \p r1 and the second \p r2,
    then \p r = <CODE>subsumes()</CODE>
    if and only if \p r1 = \p r2 = <CODE>subsumes()</CODE>;
    and \p r = <CODE>nothing()</CODE>
    if and only if one or both of \p r1 and \p r2 = <CODE>nothing()</CODE>;
  */
  Poly_Gen_Relation relation_with(const Generator& g) const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if either of the components
    of \p *this are empty.
  */
  bool is_empty() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if both of the components
    of \p *this are the universe.
  */
  bool is_universe() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if both of the components
    of \p *this are topologically closed subsets of the vector space.
  */
  bool is_topologically_closed() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this and \p y are
    componentwise disjoint.

    \exception std::invalid_argument
    Thrown if \p x and \p y are dimension-incompatible.
  */
  bool is_disjoint_from(const Partially_Reduced_Product& y) const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if a component of \p *this
    is discrete.
  */
  bool is_discrete() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if a component of \p *this
    is bounded.
  */
  bool is_bounded() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p var is constrained in
    \p *this.

    \exception std::invalid_argument
    Thrown if \p var is not a space dimension of \p *this.
  */
  bool constrains(Variable var) 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.

    \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.

    \param point
    When maximization succeeds, will be assigned a generator 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,
		Generator& point) const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this is not empty and
    \p expr is bounded from below i \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 infimum value can be reached in \p this.

    \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 infimum value can be reached in \p this.

    \param point
    When minimization succeeds, will be assigned a generator 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;

  /*! \brief
    Returns <CODE>true</CODE> if and only if each component of \p *this
    contains the corresponding component of \p y.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are dimension-incompatible.
  */
  bool contains(const Partially_Reduced_Product& y) const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if each component of \p *this
    strictly contains the corresponding component of \p y.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are dimension-incompatible.
  */
  bool strictly_contains(const Partially_Reduced_Product& y) const;

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

  //@} // Member Functions that Do Not Modify the Partially_Reduced_Product

  //! \name Space Dimension Preserving Member Functions that May Modify the Partially_Reduced_Product
  //@{

  //! Adds constraint \p c to \p *this.
  /*!
    \exception std::invalid_argument
    Thrown if \p *this and \p c are dimension-incompatible.
  */
  void add_constraint(const Constraint& c);

  /*! \brief
    Use the constraint \p c to refine \p *this.

    \param c
    The constraint to be used for refinement.

    \exception std::invalid_argument
    Thrown if \p *this and \p c are dimension-incompatible.
  */
  void refine_with_constraint(const Constraint& c);

  //! 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);

  /*! \brief
    Use the congruence \p cg to refine \p *this.

    \param cg
    The congruence to be used for refinement.

    \exception std::invalid_argument
    Thrown if \p *this and \p cg are dimension-incompatible.
  */
  void refine_with_congruence(const Congruence& cg);

  //! Adds a copy of the congruences in \p cgs to \p *this.
  /*!
    \param cgs
    The congruence system to be added.

    \exception std::invalid_argument
    Thrown if \p *this and \p cgs are dimension-incompatible.
  */
  void add_congruences(const Congruence_System& cgs);

  /*! \brief
    Use the congruences in \p cgs to refine \p *this.

    \param  cgs
    The congruences to be used for refinement.

    \exception std::invalid_argument
    Thrown if \p *this and \p cgs are dimension-incompatible.
  */
  void refine_with_congruences(const Congruence_System& cgs);

  //! Adds the congruences in \p cgs to *this.
  /*!
    \param cgs
    The congruence system to be added that may be recycled.

    \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 a copy of the constraint system in \p cs to \p *this.
  /*!
    \param cs
    The constraint system to be added.

    \exception std::invalid_argument
    Thrown if \p *this and \p cs are dimension-incompatible.
  */
  void add_constraints(const Constraint_System& cs);

  /*! \brief
    Use the constraints in \p cs to refine \p *this.

    \param  cs
     The constraints to be used for refinement.

     \exception std::invalid_argument
     Thrown if \p *this and \p cs are dimension-incompatible.
  */
  void refine_with_constraints(const Constraint_System& cs);

  //! Adds the constraint system in \p cs to \p *this.
  /*!
    \param cs
    The constraint system to be added that may be recycled.

    \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
    Computes the \ref Cylindrification "cylindrification" of \p *this with
    respect to space dimension \p var, assigning the result to \p *this.

    \param var
    The space dimension that will be unconstrained.

    \exception std::invalid_argument
    Thrown if \p var is not a space dimension of \p *this.
  */
  void unconstrain(Variable var);

  /*! \brief
    Computes the \ref Cylindrification "cylindrification" of \p *this with
    respect to the set of space dimensions \p to_be_unconstrained,
    assigning the result to \p *this.

    \param to_be_unconstrained
    The set of space dimension that will be unconstrained.

    \exception std::invalid_argument
    Thrown if \p *this is dimension-incompatible with one of the
    Variable objects contained in \p to_be_removed.
  */
  void unconstrain(const Variables_Set& to_be_unconstrained);

  /*! \brief
    Assigns to \p *this the componentwise 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 Partially_Reduced_Product& y);

  /*! \brief
    Assigns to \p *this an upper bound of \p *this and \p y
    computed on the corresponding components.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are dimension-incompatible.
  */
  void upper_bound_assign(const Partially_Reduced_Product& y);

  /*! \brief
    Assigns to \p *this an upper bound of \p *this and \p y
    computed on the corresponding components.
    If it is exact on each of the components of \p *this, <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 upper_bound_assign_if_exact(const Partially_Reduced_Product& y);

  /*! \brief
    Assigns to \p *this an approximation of the set-theoretic difference
    of \p *this and \p y.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are dimension-incompatible.
  */
  void difference_assign(const Partially_Reduced_Product& 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.

  */
  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.
  */
  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
    (see also \ref Grid_Generalized_Image "generalized affine relation".)

    \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,
				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.
   (see also \ref Grid_Generalized_Image "generalized affine relation".)

    \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,
			      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.
   (see also \ref Grid_Generalized_Image "generalized affine relation".)

    \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,
				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.
   (see also \ref Grid_Generalized_Image "generalized affine relation".)

    \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,
				   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.
    (See also \ref Grid_Time_Elapse "time-elapse".)

    \exception std::invalid_argument
    Thrown if \p *this and \p y are dimension-incompatible.
  */
  void time_elapse_assign(const Partially_Reduced_Product& y);

  //! Assigns to \p *this its topological closure.
  void topological_closure_assign();

  // TODO: Add a way to call other widenings.

  // CHECKME: This is a real widening for all the existing reduction
  // operations. When new reductions are added, this must be rechecked.

  /*! \brief
    Assigns to \p *this the result of computing the
    "widening" between \p *this and \p y.

    This widening uses either the congruence or generator systems
    depending on which of the systems describing x and y
    are up to date and minimized.

    \param y
    A product 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 widening_assign(const Partially_Reduced_Product& y,
                       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 components
    of \p *this 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>.
 */
  void add_space_dimensions_and_embed(dimension_type m);

  /*! \brief
    Adds \p m new space dimensions and does not embed the components
    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>.
  */
  void add_space_dimensions_and_project(dimension_type m);

  /*! \brief
    Assigns to the first (resp., second) component of \p *this
    the "concatenation" of the first (resp., second) components
    of \p *this and \p y, taken in this order.
    See also \ref Concatenating_Polyhedra and \ref Grid_Concatenate.

    \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 Partially_Reduced_Product& 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".

    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 <CODE>Partial_Function</CODE> 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 \p *this.

    The result is undefined if \p pfunc does not encode a partial
    function with the properties described in
    \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 Expanding_One_Dimension_of_the_Vector_Space_to_Multiple_Dimensions
    "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 Folding_Multiple_Dimensions_of_the_Vector_Space_into_One_Dimension
    "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 operator==<>(const Partially_Reduced_Product<D1, D2, R>& x,
			   const Partially_Reduced_Product<D1, D2, R>& y);

  friend std::ostream&
  Parma_Polyhedra_Library::IO_Operators::
  operator<<<>(std::ostream& s, const Partially_Reduced_Product<D1, D2, R>& dp);

  //! \name Miscellaneous Member Functions
  //@{

  //! Destructor.
  ~Partially_Reduced_Product();

  /*! \brief
    Swaps \p *this with product \p y.  (\p *this and \p y can be
    dimension-incompatible.)
  */
  void swap(Partially_Reduced_Product& y);

  PPL_OUTPUT_DECLARATIONS

  /*! \brief
    Loads from \p s an ASCII representation (as produced by
    ascii_dump(std::ostream&) const) 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
    Returns a 32-bit hash code for \p *this.

    If \p x and \p y are such that <CODE>x == y</CODE>,
    then <CODE>x.hash_code() == y.hash_code()</CODE>.
  */
  int32_t hash_code() const;

  //@} // Miscellaneous Member Functions

  //! Reduce.
  /*
    \return
    <CODE>true</CODE> if and only if either of the resulting component
    is strictly contained in the respective original.
  */
  bool reduce() const;

protected:
  //! The type of the first component.
  typedef D1 Domain1;

  //! The type of the second component.
  typedef D2 Domain2;

  //! The first component.
  D1 d1;

  //! The second component.
  D2 d2;

protected:
  //! Clears the reduced flag.
  void clear_reduced_flag() const;

  //! Sets the reduced flag.
  void set_reduced_flag() const;

  //! Return <CODE>true</CODE> if and only if the reduced flag is set.
  bool is_reduced() const;

  /*! \brief
    Flag to record whether the components are reduced with respect
    to each other and the reduction class.
  */
  bool reduced;

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  //! \name Exception Throwers
  //@{
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
protected:
  void throw_runtime_error(const char* method) const;
  void throw_invalid_argument(const char* method, const char* reason) 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(const char* method,
					     const char* reason);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  //@} // Exception Throwers
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)

};

namespace Parma_Polyhedra_Library {

/*! \brief
  This class is temporary and will be removed when template typedefs will
  be supported in C++.

  When template typedefs will be supported in C++, what now is verbosely
  denoted by Domain_Product<Domain1, Domain2>::Direct_Product will simply
  be denoted by Direct_Product<Domain1, Domain2>.
*/
template <typename D1, typename D2>
class Domain_Product {
public:
  typedef Partially_Reduced_Product<D1, D2, No_Reduction<D1, D2> >
  Direct_Product;

  typedef Partially_Reduced_Product<D1, D2, Smash_Reduction<D1, D2> >
  Smash_Product;

  typedef Partially_Reduced_Product<D1, D2, Constraints_Reduction<D1, D2> >
  Constraints_Product;
};

} // namespace Parma_Polyhedra_Library

namespace std {

//! Specializes <CODE>std::swap</CODE>.
/*! \relates Parma_Polyhedra_Library::Partially_Reduced_Product */
  template <typename D1, typename D2, typename R>
void swap(Parma_Polyhedra_Library::Partially_Reduced_Product<D1, D2, R>& x,
	  Parma_Polyhedra_Library::Partially_Reduced_Product<D1, D2, R>& y);

} // namespace std

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


/* Automatically generated from PPL source file ../src/Partially_Reduced_Product.inlines.hh line 31. */

namespace Parma_Polyhedra_Library {

template <typename D1, typename D2, typename R>
inline dimension_type
Partially_Reduced_Product<D1, D2, R>::max_space_dimension() {
  return std::min(D1::max_space_dimension(), D2::max_space_dimension());
}

template <typename D1, typename D2, typename R>
inline
Partially_Reduced_Product<D1, D2, R>
::Partially_Reduced_Product(dimension_type num_dimensions,
			    const Degenerate_Element kind)
  : d1(num_dimensions <= max_space_dimension()
       ?  num_dimensions
       : (throw_space_dimension_overflow
               ("Partially_Reduced_Product<D1, D2, R>(n, k)",
                "n exceeds the maximum "
                "allowed space dimension"),
	       0), kind),
    d2(num_dimensions, kind) {
  set_reduced_flag();
}

template <typename D1, typename D2, typename R>
inline
Partially_Reduced_Product<D1, D2, R>
::Partially_Reduced_Product(const Congruence_System& ccgs)
  : d1((ccgs.space_dimension() <= max_space_dimension())
       ?  ccgs
       : (throw_space_dimension_overflow
          ("Partially_Reduced_Product<D1, D2, R>(n, k)",
           "the space dimension of ccgs "
           "exceeds the maximum allowed "
           "space dimension"), ccgs)),
    d2(ccgs) {
  clear_reduced_flag();
}

template <typename D1, typename D2, typename R>
inline
Partially_Reduced_Product<D1, D2, R>
::Partially_Reduced_Product(Congruence_System& cgs)
  : d1((cgs.space_dimension() <= max_space_dimension())
       ? const_cast<const Congruence_System&>(cgs)
       : (throw_space_dimension_overflow
          ("Partially_Reduced_Product<D1, D2, R>(n, k)",
           "the space dimension of cgs "
           "exceeds the maximum allowed "
           "space dimension"), cgs)),
    d2(cgs) {
  clear_reduced_flag();
}

template <typename D1, typename D2, typename R>
inline
Partially_Reduced_Product<D1, D2, R>
::Partially_Reduced_Product(const Constraint_System& ccs)
  : d1((ccs.space_dimension() <= max_space_dimension())
       ?  ccs
       : (throw_space_dimension_overflow
          ("Partially_Reduced_Product<D1, D2, R>(n, k)",
           "the space dimension of ccs "
           "exceeds the maximum allowed "
           "space dimension"), ccs)),
    d2(ccs) {
  clear_reduced_flag();
}

template <typename D1, typename D2, typename R>
inline
Partially_Reduced_Product<D1, D2, R>
::Partially_Reduced_Product(Constraint_System& cs)
  : d1((cs.space_dimension() <= max_space_dimension())
       ? const_cast<const Constraint_System&>(cs)
       : (throw_space_dimension_overflow
          ("Partially_Reduced_Product<D1, D2, R>(n, k)",
           "the space dimension of cs "
           "exceeds the maximum allowed "
           "space dimension"), cs)),
    d2(cs) {
  clear_reduced_flag();
}

template <typename D1, typename D2, typename R>
inline
Partially_Reduced_Product<D1, D2, R>
::Partially_Reduced_Product(const C_Polyhedron& ph,
                            Complexity_Class complexity)
  : d1((ph.space_dimension() <= max_space_dimension())
       ? ph
       : (throw_space_dimension_overflow
          ("Partially_Reduced_Product<D1, D2, R>(n, k)",
           "the space dimension of ph "
           "exceeds the maximum allowed "
           "space dimension"), ph), complexity),
   d2(ph, complexity) {
  set_reduced_flag();
}

template <typename D1, typename D2, typename R>
inline
Partially_Reduced_Product<D1, D2, R>
::Partially_Reduced_Product(const NNC_Polyhedron& ph,
                            Complexity_Class complexity)
 : d1((ph.space_dimension() <= max_space_dimension())
       ? ph
       : (throw_space_dimension_overflow
          ("Partially_Reduced_Product<D1, D2, R>(n, k)",
           "the space dimension of ph "
           "exceeds the maximum allowed "
           "space dimension"), ph), complexity),
   d2(ph, complexity) {
  set_reduced_flag();
}

template <typename D1, typename D2, typename R>
inline
Partially_Reduced_Product<D1, D2, R>
::Partially_Reduced_Product(const Grid& gr, Complexity_Class)
 : d1((gr.space_dimension() <= max_space_dimension())
       ? gr
       : (throw_space_dimension_overflow
          ("Partially_Reduced_Product<D1, D2, R>(n, k)",
           "the space dimension of gr "
           "exceeds the maximum allowed "
           "space dimension"), gr)),
   d2(gr) {
  set_reduced_flag();
}

template <typename D1, typename D2, typename R>
template <typename Interval>
inline
Partially_Reduced_Product<D1, D2, R>
::Partially_Reduced_Product(const Box<Interval>& box, Complexity_Class)
 : d1((box.space_dimension() <= max_space_dimension())
       ? box
       : (throw_space_dimension_overflow
          ("Partially_Reduced_Product<D1, D2, R>(n, k)",
           "the space dimension of box "
           "exceeds the maximum allowed "
           "space dimension"), box)),
   d2(box) {
  set_reduced_flag();
}

template <typename D1, typename D2, typename R>
template <typename U>
inline
Partially_Reduced_Product<D1, D2, R>
::Partially_Reduced_Product(const BD_Shape<U>& bd, Complexity_Class)
 : d1((bd.space_dimension() <= max_space_dimension())
       ? bd
       : (throw_space_dimension_overflow
          ("Partially_Reduced_Product<D1, D2, R>(n, k)",
           "the space dimension of bd "
           "exceeds the maximum allowed "
           "space dimension"), bd)),
   d2(bd) {
  set_reduced_flag();
}

template <typename D1, typename D2, typename R>
template <typename U>
inline
Partially_Reduced_Product<D1, D2, R>
::Partially_Reduced_Product(const Octagonal_Shape<U>& os, Complexity_Class)
 : d1((os.space_dimension() <= max_space_dimension())
       ? os
       : (throw_space_dimension_overflow
          ("Partially_Reduced_Product<D1, D2, R>(n, k)",
           "the space dimension of os "
           "exceeds the maximum allowed "
           "space dimension"), os)),
   d2(os) {
  set_reduced_flag();
}

template <typename D1, typename D2, typename R>
inline
Partially_Reduced_Product<D1, D2, R>
::Partially_Reduced_Product(const Partially_Reduced_Product& y,
                            Complexity_Class)
  : d1(y.d1), d2(y.d2) {
  reduced = y.reduced;
}

template <typename D1, typename D2, typename R>
inline
Partially_Reduced_Product<D1, D2, R>::~Partially_Reduced_Product() {
}

template <typename D1, typename D2, typename R>
inline memory_size_type
Partially_Reduced_Product<D1, D2, R>::external_memory_in_bytes() const {
  return d1.external_memory_in_bytes() + d2.external_memory_in_bytes();
}

template <typename D1, typename D2, typename R>
inline memory_size_type
Partially_Reduced_Product<D1, D2, R>::total_memory_in_bytes() const {
  return sizeof(*this) + external_memory_in_bytes();
}

template <typename D1, typename D2, typename R>
inline dimension_type
Partially_Reduced_Product<D1, D2, R>::space_dimension() const {
  assert(d1.space_dimension() == d2.space_dimension());
  return d1.space_dimension();
}

template <typename D1, typename D2, typename R>
inline dimension_type
Partially_Reduced_Product<D1, D2, R>::affine_dimension() const {
  reduce();
  const dimension_type d1_dim = d1.affine_dimension();
  const dimension_type d2_dim = d2.affine_dimension();
  return std::min(d1_dim, d2_dim);
}

template <typename D1, typename D2, typename R>
inline void
Partially_Reduced_Product<D1, D2, R>
::unconstrain(const Variable var) {
  reduce();
  d1.unconstrain(var);
  d2.unconstrain(var);
}

template <typename D1, typename D2, typename R>
inline void
Partially_Reduced_Product<D1, D2, R>
::unconstrain(const Variables_Set& to_be_unconstrained) {
  reduce();
  d1.unconstrain(to_be_unconstrained);
  d2.unconstrain(to_be_unconstrained);
}

template <typename D1, typename D2, typename R>
inline void
Partially_Reduced_Product<D1, D2, R>
::intersection_assign(const Partially_Reduced_Product& y) {
  d1.intersection_assign(y.d1);
  d2.intersection_assign(y.d2);
  clear_reduced_flag();
}

template <typename D1, typename D2, typename R>
inline void
Partially_Reduced_Product<D1, D2, R>
::difference_assign(const Partially_Reduced_Product& y) {
  reduce();
  y.reduce();
  d1.difference_assign(y.d1);
  d2.difference_assign(y.d2);
  clear_reduced_flag();
}

template <typename D1, typename D2, typename R>
inline void
Partially_Reduced_Product<D1, D2, R>
::upper_bound_assign(const Partially_Reduced_Product& y) {
  reduce();
  y.reduce();
  d1.upper_bound_assign(y.d1);
  d2.upper_bound_assign(y.d2);
  // CHECKME: if upper_bound_assign is not a least_upper_bound
  //          it may not be reduced.
  // clear_reduced_flag();
}

template <typename D1, typename D2, typename R>
inline bool
Partially_Reduced_Product<D1, D2, R>
::upper_bound_assign_if_exact(const Partially_Reduced_Product& y) {
  reduce();
  y.reduce();
  D1 d1_copy = d1;
  bool ub_exact = d1_copy.upper_bound_assign_if_exact(y.d1);
  if (!ub_exact)
    return false;
  ub_exact = d2.upper_bound_assign_if_exact(y.d2);
  if (!ub_exact)
    return false;
  std::swap(d1,d1_copy);
  return true;
}

template <typename D1, typename D2, typename R>
inline void
Partially_Reduced_Product<D1, D2, R>
::affine_image(Variable var,
	       const Linear_Expression& expr,
	       Coefficient_traits::const_reference denominator) {
  d1.affine_image(var, expr, denominator);
  d2.affine_image(var, expr, denominator);
}

template <typename D1, typename D2, typename R>
inline void
Partially_Reduced_Product<D1, D2, R>
::affine_preimage(Variable var,
		  const Linear_Expression& expr,
		  Coefficient_traits::const_reference denominator) {
  d1.affine_preimage(var, expr, denominator);
  d2.affine_preimage(var, expr, denominator);
}

template <typename D1, typename D2, typename R>
inline void
Partially_Reduced_Product<D1, D2, R>
::generalized_affine_image(Variable var,
			   const Relation_Symbol relsym,
			   const Linear_Expression& expr,
			   Coefficient_traits::const_reference denominator) {
  d1.generalized_affine_image(var, relsym, expr, denominator);
  d2.generalized_affine_image(var, relsym, expr, denominator);
}

template <typename D1, typename D2, typename R>
inline void
Partially_Reduced_Product<D1, D2, R>
::generalized_affine_preimage(Variable var,
			      const Relation_Symbol relsym,
			      const Linear_Expression& expr,
			      Coefficient_traits::const_reference denominator) {
  d1.generalized_affine_preimage(var, relsym, expr, denominator);
  d2.generalized_affine_preimage(var, relsym, expr, denominator);
}

template <typename D1, typename D2, typename R>
inline void
Partially_Reduced_Product<D1, D2, R>
::generalized_affine_image(const Linear_Expression& lhs,
			   const Relation_Symbol relsym,
			   const Linear_Expression& rhs) {
  d1.generalized_affine_image(lhs, relsym, rhs);
  d2.generalized_affine_image(lhs, relsym, rhs);
}

template <typename D1, typename D2, typename R>
inline void
Partially_Reduced_Product<D1, D2, R>
::generalized_affine_preimage(const Linear_Expression& lhs,
                              const Relation_Symbol relsym,
                              const Linear_Expression& rhs) {
  d1.generalized_affine_preimage(lhs, relsym, rhs);
  d2.generalized_affine_preimage(lhs, relsym, rhs);
}


template <typename D1, typename D2, typename R>
inline void
Partially_Reduced_Product<D1, D2, R>
::bounded_affine_image(Variable var,
                       const Linear_Expression& lb_expr,
                       const Linear_Expression& ub_expr,
                       Coefficient_traits::const_reference denominator) {
  d1.bounded_affine_image(var, lb_expr, ub_expr, denominator);
  d2.bounded_affine_image(var, lb_expr, ub_expr, denominator);
  clear_reduced_flag();
}

template <typename D1, typename D2, typename R>
inline void
Partially_Reduced_Product<D1, D2, R>
::bounded_affine_preimage(Variable var,
                          const Linear_Expression& lb_expr,
                          const Linear_Expression& ub_expr,
                          Coefficient_traits::const_reference denominator) {
  d1.bounded_affine_preimage(var, lb_expr, ub_expr, denominator);
  d2.bounded_affine_preimage(var, lb_expr, ub_expr, denominator);
  clear_reduced_flag();
}

template <typename D1, typename D2, typename R>
inline void
Partially_Reduced_Product<D1, D2, R>
::time_elapse_assign(const Partially_Reduced_Product& y) {
  reduce();
  y.reduce();
  d1.time_elapse_assign(y.d1);
  d2.time_elapse_assign(y.d2);
}

template <typename D1, typename D2, typename R>
inline void
Partially_Reduced_Product<D1, D2, R>::topological_closure_assign() {
  d1.topological_closure_assign();
  d2.topological_closure_assign();
}

template <typename D1, typename D2, typename R>
inline void
Partially_Reduced_Product<D1, D2, R>::swap(Partially_Reduced_Product& y) {
  std::swap(d1, y.d1);
  std::swap(d2, y.d2);
  std::swap(reduced, y.reduced);
}

template <typename D1, typename D2, typename R>
inline void
Partially_Reduced_Product<D1, D2, R>::add_constraint(const Constraint& c) {
  d1.add_constraint(c);
  d2.add_constraint(c);
  clear_reduced_flag();
}

template <typename D1, typename D2, typename R>
inline void
Partially_Reduced_Product<D1, D2, R>::refine_with_constraint(const Constraint& c) {
  d1.refine_with_constraint(c);
  d2.refine_with_constraint(c);
  clear_reduced_flag();
}

template <typename D1, typename D2, typename R>
inline void
Partially_Reduced_Product<D1, D2, R>::add_congruence(const Congruence& cg) {
  d1.add_congruence(cg);
  d2.add_congruence(cg);
  clear_reduced_flag();
}

template <typename D1, typename D2, typename R>
inline void
Partially_Reduced_Product<D1, D2, R>::refine_with_congruence(const Congruence& cg) {
  d1.refine_with_congruence(cg);
  d2.refine_with_congruence(cg);
  clear_reduced_flag();
}

template <typename D1, typename D2, typename R>
inline void
Partially_Reduced_Product<D1, D2, R>
::add_constraints(const Constraint_System& cs) {
  d1.add_constraints(cs);
  d2.add_constraints(cs);
  clear_reduced_flag();
}

template <typename D1, typename D2, typename R>
inline void
Partially_Reduced_Product<D1, D2, R>
::refine_with_constraints(const Constraint_System& cs) {
  d1.refine_with_constraints(cs);
  d2.refine_with_constraints(cs);
  clear_reduced_flag();
}

template <typename D1, typename D2, typename R>
inline void
Partially_Reduced_Product<D1, D2, R>
::add_congruences(const Congruence_System& cgs) {
  d1.add_congruences(cgs);
  d2.add_congruences(cgs);
  clear_reduced_flag();
}

template <typename D1, typename D2, typename R>
inline void
Partially_Reduced_Product<D1, D2, R>
::refine_with_congruences(const Congruence_System& cgs) {
  d1.refine_with_congruences(cgs);
  d2.refine_with_congruences(cgs);
  clear_reduced_flag();
}

template <typename D1, typename D2, typename R>
inline Partially_Reduced_Product<D1, D2, R>&
Partially_Reduced_Product<D1, D2, R>
::operator=(const Partially_Reduced_Product& y) {
  d1 = y.d1;
  d2 = y.d2;
  reduced = y.reduced;
  return *this;
}

template <typename D1, typename D2, typename R>
inline const D1&
Partially_Reduced_Product<D1, D2, R>::domain1() const {
  reduce();
  return d1;
}

template <typename D1, typename D2, typename R>
inline const D2&
Partially_Reduced_Product<D1, D2, R>::domain2() const {
  reduce();
  return d2;
}

template <typename D1, typename D2, typename R>
inline bool
Partially_Reduced_Product<D1, D2, R>::is_empty() const {
  reduce();
  return d1.is_empty() || d2.is_empty();
}

template <typename D1, typename D2, typename R>
inline bool
Partially_Reduced_Product<D1, D2, R>::is_universe() const {
  return d1.is_universe() && d2.is_universe();
}

template <typename D1, typename D2, typename R>
inline bool
Partially_Reduced_Product<D1, D2, R>::is_topologically_closed() const {
  reduce();
  return d1.is_topologically_closed() && d2.is_topologically_closed();
}

template <typename D1, typename D2, typename R>
inline bool
Partially_Reduced_Product<D1, D2, R>
::is_disjoint_from(const Partially_Reduced_Product& y) const {
  reduce();
  y.reduce();
  return d1.is_disjoint_from(y.d1) || d2.is_disjoint_from(y.d2);
}

template <typename D1, typename D2, typename R>
inline bool
Partially_Reduced_Product<D1, D2, R>::is_discrete() const {
  reduce();
  return d1.is_discrete() || d2.is_discrete();
}

template <typename D1, typename D2, typename R>
inline bool
Partially_Reduced_Product<D1, D2, R>::is_bounded() const {
  reduce();
  return d1.is_bounded() || d2.is_bounded();
}

template <typename D1, typename D2, typename R>
inline bool
Partially_Reduced_Product<D1, D2, R>
::bounds_from_above(const Linear_Expression& expr) const {
  reduce();
  return d1.bounds_from_above(expr) || d2.bounds_from_above(expr);
}

template <typename D1, typename D2, typename R>
inline bool
Partially_Reduced_Product<D1, D2, R>
::bounds_from_below(const Linear_Expression& expr) const {
  reduce();
  return d1.bounds_from_below(expr) || d2.bounds_from_below(expr);
}

template <typename D1, typename D2, typename R>
inline bool
Partially_Reduced_Product<D1, D2, R>::constrains(Variable var) const {
  reduce();
  return d1.constrains(var) || d2.constrains(var);
}

template <typename D1, typename D2, typename R>
inline void
Partially_Reduced_Product<D1, D2, R>
::widening_assign(const Partially_Reduced_Product& y,
                  unsigned* tp) {
  reduce();
  y.reduce();
  d1.widening_assign(y.d1, tp);
  d2.widening_assign(y.d2, tp);
}

template <typename D1, typename D2, typename R>
inline void
Partially_Reduced_Product<D1, D2, R>
::add_space_dimensions_and_embed(dimension_type m) {
  d1.add_space_dimensions_and_embed(m);
  d2.add_space_dimensions_and_embed(m);
}

template <typename D1, typename D2, typename R>
inline void
Partially_Reduced_Product<D1, D2, R>
::add_space_dimensions_and_project(dimension_type m) {
  d1.add_space_dimensions_and_project(m);
  d2.add_space_dimensions_and_project(m);
}

template <typename D1, typename D2, typename R>
inline void
Partially_Reduced_Product<D1, D2, R>
::concatenate_assign(const Partially_Reduced_Product& y) {
  d1.concatenate_assign(y.d1);
  d2.concatenate_assign(y.d2);
  if (!is_reduced() || !y.is_reduced())
    clear_reduced_flag();
}

template <typename D1, typename D2, typename R>
inline void
Partially_Reduced_Product<D1, D2, R>
::remove_space_dimensions(const Variables_Set& to_be_removed) {
  d1.remove_space_dimensions(to_be_removed);
  d2.remove_space_dimensions(to_be_removed);
}

template <typename D1, typename D2, typename R>
inline void
Partially_Reduced_Product<D1, D2, R>
::remove_higher_space_dimensions(dimension_type new_dimension) {
  d1.remove_higher_space_dimensions(new_dimension);
  d2.remove_higher_space_dimensions(new_dimension);
}

template <typename D1, typename D2, typename R>
template <typename Partial_Function>
inline void
Partially_Reduced_Product<D1, D2, R>
::map_space_dimensions(const Partial_Function& pfunc) {
  d1.map_space_dimensions(pfunc);
  d2.map_space_dimensions(pfunc);
}

template <typename D1, typename D2, typename R>
inline void
Partially_Reduced_Product<D1, D2, R>
::expand_space_dimension(Variable var, dimension_type m) {
  d1.expand_space_dimension(var, m);
  d2.expand_space_dimension(var, m);
}

template <typename D1, typename D2, typename R>
inline void
Partially_Reduced_Product<D1, D2, R>
::fold_space_dimensions(const Variables_Set& to_be_folded,
			Variable var) {
  d1.fold_space_dimensions(to_be_folded, var);
  d2.fold_space_dimensions(to_be_folded, var);
}

template <typename D1, typename D2, typename R>
inline bool
Partially_Reduced_Product<D1, D2, R>
::contains(const Partially_Reduced_Product& y) const {
  reduce();
  y.reduce();
  return d1.contains(y.d1) && d2.contains(y.d2);
}

template <typename D1, typename D2, typename R>
inline bool
Partially_Reduced_Product<D1, D2, R>
::strictly_contains(const Partially_Reduced_Product& y) const {
  reduce();
  y.reduce();
  return (d1.contains(y.d1) && d2.strictly_contains(y.d2))
    || (d2.contains(y.d2) && d1.strictly_contains(y.d1));
}

template <typename D1, typename D2, typename R>
inline bool
Partially_Reduced_Product<D1, D2, R>::reduce() const {
  Partially_Reduced_Product& dp
    = const_cast<Partially_Reduced_Product&>(*this);
  if (dp.is_reduced())
    return false;
  R r;
  r.product_reduce(dp.d1, dp.d2);
  set_reduced_flag();
  return true;
}

template <typename D1, typename D2, typename R>
inline bool
Partially_Reduced_Product<D1, D2, R>::is_reduced() const {
  return reduced;
}

template <typename D1, typename D2, typename R>
inline void
Partially_Reduced_Product<D1, D2, R>::clear_reduced_flag() const {
  const_cast<Partially_Reduced_Product&>(*this).reduced = false;
}

template <typename D1, typename D2, typename R>
inline void
Partially_Reduced_Product<D1, D2, R>::set_reduced_flag() const {
  const_cast<Partially_Reduced_Product&>(*this).reduced = true;
}

PPL_OUTPUT_3_PARAM_TEMPLATE_DEFINITIONS(D1, D2, R, Partially_Reduced_Product)

template <typename D1, typename D2, typename R>
inline void
Partially_Reduced_Product<D1, D2, R>::ascii_dump(std::ostream& s) const {
  const char yes = '+';
  const char no = '-';
  s << "Partially_Reduced_Product\n";
  s << (reduced ? yes : no) << "reduced\n";
  s << "Domain 1:\n";
  d1.ascii_dump(s);
  s << "Domain 2:\n";
  d2.ascii_dump(s);
}

template <typename D1, typename D2, typename R>
inline int32_t
Partially_Reduced_Product<D1, D2, R>::hash_code() const {
  return space_dimension() & 0x7fffffff;
}

/*! \relates Parma_Polyhedra_Library::Partially_Reduced_Product */
template <typename D1, typename D2, typename R>
inline bool
operator==(const Partially_Reduced_Product<D1, D2, R>& x,
	   const Partially_Reduced_Product<D1, D2, R>& y) {
  x.reduce();
  y.reduce();
  return x.d1 == y.d1 && x.d2 == y.d2;
}

/*! \relates Parma_Polyhedra_Library::Partially_Reduced_Product */
template <typename D1, typename D2, typename R>
inline bool
operator!=(const Partially_Reduced_Product<D1, D2, R>& x,
	   const Partially_Reduced_Product<D1, D2, R>& y) {
  return !(x == y);
}

/*! \relates Parma_Polyhedra_Library::Partially_Reduced_Product */
template <typename D1, typename D2, typename R>
inline std::ostream&
IO_Operators::operator<<(std::ostream& s, const Partially_Reduced_Product<D1, D2, R>& pd) {
  return s << "Domain 1:\n"
	   << pd.d1
	   << "Domain 2:\n"
	   << pd.d2;
}

template <typename D1, typename D2, typename R>
void
Partially_Reduced_Product<D1, D2, R>::throw_space_dimension_overflow(const char* method,
                                                                     const char* reason) {
  std::ostringstream s;
  s << "Partially_Reduced_Product<D1, D2, R>::" << method << ":" << std::endl
    << reason << ".";
  throw std::length_error(s.str());
}

} // namespace Parma_Polyhedra_Library

namespace Parma_Polyhedra_Library {

template <typename D1, typename D2>
inline
No_Reduction<D1, D2>::No_Reduction() {
}

template <typename D1, typename D2>
void No_Reduction<D1, D2>::product_reduce(D1&, D2&) {
}

template <typename D1, typename D2>
inline
No_Reduction<D1, D2>::~No_Reduction() {
}

template <typename D1, typename D2>
inline
Smash_Reduction<D1, D2>::Smash_Reduction() {
}

template <typename D1, typename D2>
inline
Smash_Reduction<D1, D2>::~Smash_Reduction() {
}

template <typename D1, typename D2>
inline
Constraints_Reduction<D1, D2>::Constraints_Reduction() {
}

template <typename D1, typename D2>
inline
Constraints_Reduction<D1, D2>::~Constraints_Reduction() {
}

} // namespace Parma_Polyhedra_Library

/*! \relates Parma_Polyhedra_Library::Partially_Reduced_Product */
template <typename D1, typename D2, typename R>
inline void
std::swap(Parma_Polyhedra_Library::Partially_Reduced_Product<D1, D2, R>& x,
	  Parma_Polyhedra_Library::Partially_Reduced_Product<D1, D2, R>& y) {
  x.swap(y);
}

/* Automatically generated from PPL source file ../src/Partially_Reduced_Product.templates.hh line 1. */
/* Partially_Reduced_Product class implementation:
   non-inline template functions.
*/


/* Automatically generated from PPL source file ../src/Partially_Reduced_Product.templates.hh line 30. */
#include <algorithm>
#include <deque>

namespace Parma_Polyhedra_Library {

template <typename D1, typename D2, typename R>
template <typename E1, typename E2, typename S>
inline
Partially_Reduced_Product<D1, D2, R>
::Partially_Reduced_Product(const Partially_Reduced_Product<E1, E2, S>& y,
                            Complexity_Class complexity)
  : d1((y.space_dimension() > max_space_dimension())
       ? (throw_space_dimension_overflow
       ("Partially_Reduced_Product<D1, D2, R>(y)",
        "the space dimension of y "
        "exceeds the maximum allowed "
        "space dimension"), 0)
       : y.space_dimension()),
    d2(y.space_dimension()) {
  Partially_Reduced_Product<D1, D2, R> x1(y.domain1(), complexity);
  const Partially_Reduced_Product<D1, D2, R> x2(y.domain2(), complexity);
  x1.intersection_assign(x2);
  d1.swap(x1.d1);
  d2.swap(x1.d2);
  /* Even if y is reduced, the built product may not be reduced as
     the reduction method may have changed (i.e., S != R). */
  reduced = false;
}

template <typename D1, typename D2, typename R>
Constraint_System
Partially_Reduced_Product<D1, D2, R>::constraints() const {
  reduce();
  Constraint_System cs = d2.constraints();
  const Constraint_System& cs1 = d1.constraints();
  for (Constraint_System::const_iterator i = cs1.begin(),
	 cs_end = cs1.end(); i != cs_end; ++i)
    cs.insert(*i);
  return cs;
}

template <typename D1, typename D2, typename R>
Constraint_System
Partially_Reduced_Product<D1, D2, R>::minimized_constraints() const {
  reduce();
  Constraint_System cs = d2.constraints();
  const Constraint_System& cs1 = d1.constraints();
  for (Constraint_System::const_iterator i = cs1.begin(),
	 cs_end = cs1.end(); i != cs_end; ++i)
    cs.insert(*i);
  if (cs.has_strict_inequalities()) {
    NNC_Polyhedron ph(cs);
    return ph.minimized_constraints();
  }
  else {
    C_Polyhedron ph(cs);
    return ph.minimized_constraints();
  }
}

template <typename D1, typename D2, typename R>
Congruence_System
Partially_Reduced_Product<D1, D2, R>::congruences() const {
  reduce();
  Congruence_System cgs = d2.congruences();
  const Congruence_System& cgs1 = d1.congruences();
  for (Congruence_System::const_iterator i = cgs1.begin(),
	 cgs_end = cgs1.end(); i != cgs_end; ++i)
    cgs.insert(*i);
  return cgs;
}

template <typename D1, typename D2, typename R>
Congruence_System
Partially_Reduced_Product<D1, D2, R>::minimized_congruences() const {
  reduce();
  Congruence_System cgs = d2.congruences();
  const Congruence_System& cgs1 = d1.congruences();
  for (Congruence_System::const_iterator i = cgs1.begin(),
	 cgs_end = cgs1.end(); i != cgs_end; ++i)
    cgs.insert(*i);
  Grid gr(cgs);
  return gr.minimized_congruences();
}

template <typename D1, typename D2, typename R>
void
Partially_Reduced_Product<D1, D2, R>
::add_recycled_constraints(Constraint_System& cs) {
  if (d1.can_recycle_constraint_systems()) {
    d2.refine_with_constraints(cs);
    d1.add_recycled_constraints(cs);
  }
  else
    if (d2.can_recycle_constraint_systems()) {
      d1.refine_with_constraints(cs);
      d2.add_recycled_constraints(cs);
    }
    else {
      d1.add_constraints(cs);
      d2.add_constraints(cs);
    }
  clear_reduced_flag();
}

template <typename D1, typename D2, typename R>
void
Partially_Reduced_Product<D1, D2, R>
::add_recycled_congruences(Congruence_System& cgs) {
  if (d1.can_recycle_congruence_systems()) {
    d2.refine_with_congruences(cgs);
    d1.add_recycled_congruences(cgs);
  }
  else
    if (d2.can_recycle_congruence_systems()) {
      d1.refine_with_congruences(cgs);
      d2.add_recycled_congruences(cgs);
    }
    else {
      d1.add_congruences(cgs);
      d2.add_congruences(cgs);
    }
  clear_reduced_flag();
}

template <typename D1, typename D2, typename R>
Poly_Gen_Relation
Partially_Reduced_Product<D1, D2, R>
::relation_with(const Generator& g) const {
  reduce();
  if (Poly_Gen_Relation::nothing() == d1.relation_with(g)
      || Poly_Gen_Relation::nothing() == d2.relation_with(g))
    return Poly_Gen_Relation::nothing();
  else
    return Poly_Gen_Relation::subsumes();
}

template <typename D1, typename D2, typename R>
Poly_Con_Relation
Partially_Reduced_Product<D1, D2, R>
::relation_with(const Constraint& c) const {
  reduce();
  Poly_Con_Relation relation1 = d1.relation_with(c);
  Poly_Con_Relation relation2 = d2.relation_with(c);

  Poly_Con_Relation result = Poly_Con_Relation::nothing();

  if (relation1.implies(Poly_Con_Relation::is_included()))
    result = result && Poly_Con_Relation::is_included();
  else if (relation2.implies(Poly_Con_Relation::is_included()))
    result = result && Poly_Con_Relation::is_included();
  if (relation1.implies(Poly_Con_Relation::saturates()))
    result = result && Poly_Con_Relation::saturates();
  else if (relation2.implies(Poly_Con_Relation::saturates()))
    result = result && Poly_Con_Relation::saturates();
  if (relation1.implies(Poly_Con_Relation::is_disjoint()))
    result = result && Poly_Con_Relation::is_disjoint();
  else if (relation2.implies(Poly_Con_Relation::is_disjoint()))
    result = result && Poly_Con_Relation::is_disjoint();

  return result;
}

template <typename D1, typename D2, typename R>
Poly_Con_Relation
Partially_Reduced_Product<D1, D2, R>
::relation_with(const Congruence& cg) const {
  reduce();
  Poly_Con_Relation relation1 = d1.relation_with(cg);
  Poly_Con_Relation relation2 = d2.relation_with(cg);

  Poly_Con_Relation result = Poly_Con_Relation::nothing();

  if (relation1.implies(Poly_Con_Relation::is_included()))
    result = result && Poly_Con_Relation::is_included();
  else if (relation2.implies(Poly_Con_Relation::is_included()))
    result = result && Poly_Con_Relation::is_included();
  if (relation1.implies(Poly_Con_Relation::saturates()))
    result = result && Poly_Con_Relation::saturates();
  else if (relation2.implies(Poly_Con_Relation::saturates()))
    result = result && Poly_Con_Relation::saturates();
  if (relation1.implies(Poly_Con_Relation::is_disjoint()))
    result = result && Poly_Con_Relation::is_disjoint();
  else if (relation2.implies(Poly_Con_Relation::is_disjoint()))
    result = result && Poly_Con_Relation::is_disjoint();

  return result;
}

template <typename D1, typename D2, typename R>
bool
Partially_Reduced_Product<D1, D2, R>
::maximize(const Linear_Expression& expr,
	   Coefficient& sup_n,
	   Coefficient& sup_d,
	   bool& maximum) const {
  // If one component is already empty, then there is no need to reduce.
  if (d1.is_empty() || d2.is_empty())
    return false;

  // The product is_empty() test also reduces the product.
  if (is_empty())
    return false;
  assert(reduced);

  PPL_DIRTY_TEMP_COEFFICIENT(sup1_n);
  PPL_DIRTY_TEMP_COEFFICIENT(sup1_d);
  PPL_DIRTY_TEMP_COEFFICIENT(sup2_n);
  PPL_DIRTY_TEMP_COEFFICIENT(sup2_d);
  bool maximum1;
  bool maximum2;
  bool r1 = d1.maximize(expr, sup1_n, sup1_d, maximum1);
  bool r2 = d2.maximize(expr, sup2_n, sup2_d, maximum2);
  // If neither is bounded from above, return false.
  if (!r1 && !r2)
    return false;
  // If only d2 is bounded from above, then use the values for d2.
  if (!r1) {
    sup_n = sup2_n;
    sup_d = sup2_d;
    maximum = maximum2;
    return true;
  }
  // If only d1 is bounded from above, then use the values for d1.
  if (!r2) {
    sup_n = sup1_n;
    sup_d = sup1_d;
    maximum = maximum1;
    return true;
  }
  // If both d1 and d2 are bounded from above, then use the minimum values.
  if (sup2_d * sup1_n >= sup1_d * sup2_n) {
    sup_n = sup1_n;
    sup_d = sup1_d;
    maximum = maximum1;
  }
  else {
    sup_n = sup2_n;
    sup_d = sup2_d;
    maximum = maximum2;
  }
  return true;
 }

template <typename D1, typename D2, typename R>
bool
Partially_Reduced_Product<D1, D2, R>
::minimize(const Linear_Expression& expr,
	   Coefficient& inf_n,
	   Coefficient& inf_d,
	   bool& minimum) const {
  // If one component is already empty, then there is no need to reduce.
  if (d1.is_empty() || d2.is_empty())
    return false;

  // The product is_empty() test also reduces the product.
  if (is_empty())
    return false;
  assert(reduced);

  PPL_DIRTY_TEMP_COEFFICIENT(inf1_n);
  PPL_DIRTY_TEMP_COEFFICIENT(inf1_d);
  PPL_DIRTY_TEMP_COEFFICIENT(inf2_n);
  PPL_DIRTY_TEMP_COEFFICIENT(inf2_d);
  bool minimum1;
  bool minimum2;
  bool r1 = d1.minimize(expr, inf1_n, inf1_d, minimum1);
  bool r2 = d2.minimize(expr, inf2_n, inf2_d, minimum2);
  // If neither is bounded from below, return false.
  if (!r1 && !r2)
    return false;
  // If only d2 is bounded from below, then use the values for d2.
  if (!r1) {
    inf_n = inf2_n;
    inf_d = inf2_d;
    minimum = minimum2;
    return true;
  }
  // If only d1 is bounded from below, then use the values for d1.
  if (!r2) {
    inf_n = inf1_n;
    inf_d = inf1_d;
    minimum = minimum1;
    return true;
  }
  // If both d1 and d2 are bounded from below, then use the minimum values.
  if (inf2_d * inf1_n <= inf1_d * inf2_n) {
    inf_n = inf1_n;
    inf_d = inf1_d;
    minimum = minimum1;
  }
  else {
    inf_n = inf2_n;
    inf_d = inf2_d;
    minimum = minimum2;
  }
  return true;
 }

template <typename D1, typename D2, typename R>
bool
Partially_Reduced_Product<D1, D2, R>
::maximize(const Linear_Expression& expr,
	   Coefficient& sup_n,
	   Coefficient& sup_d,
	   bool& maximum,
	   Generator& pnt) const {
  // If one component is already empty, then there is no need to reduce.
  if (d1.is_empty() || d2.is_empty())
    return false;

  // The product is_empty() test also reduces the product.
  if (is_empty())
    return false;
  assert(reduced);

  PPL_DIRTY_TEMP_COEFFICIENT(sup1_n);
  PPL_DIRTY_TEMP_COEFFICIENT(sup1_d);
  PPL_DIRTY_TEMP_COEFFICIENT(sup2_n);
  PPL_DIRTY_TEMP_COEFFICIENT(sup2_d);
  bool maximum1;
  bool maximum2;
  Generator pnt1(point());
  Generator pnt2(point());
  bool r1 = d1.maximize(expr, sup1_n, sup1_d, maximum1, pnt1);
  bool r2 = d2.maximize(expr, sup2_n, sup2_d, maximum2, pnt2);
  // If neither is bounded from above, return false.
  if (!r1 && !r2)
    return false;
  // If only d2 is bounded from above, then use the values for d2.
  if (!r1) {
    sup_n = sup2_n;
    sup_d = sup2_d;
    maximum = maximum2;
    pnt = pnt2;
    return true;
  }
  // If only d1 is bounded from above, then use the values for d1.
  if (!r2) {
    sup_n = sup1_n;
    sup_d = sup1_d;
    maximum = maximum1;
    pnt = pnt1;
    return true;
  }
  // If both d1 and d2 are bounded from above, then use the minimum values.
  if (sup2_d * sup1_n >= sup1_d * sup2_n) {
    sup_n = sup1_n;
    sup_d = sup1_d;
    maximum = maximum1;
    pnt = pnt1;
  }
  else {
    sup_n = sup2_n;
    sup_d = sup2_d;
    maximum = maximum2;
    pnt = pnt2;
  }
  return true;
 }

template <typename D1, typename D2, typename R>
bool
Partially_Reduced_Product<D1, D2, R>
::minimize(const Linear_Expression& expr,
	   Coefficient& inf_n,
	   Coefficient& inf_d,
	   bool& minimum,
	   Generator& pnt) const {
  // If one component is already empty, then there is no need to reduce.
  if (d1.is_empty() || d2.is_empty())
    return false;

  // The product is_empty() test also reduces the product.
  if (is_empty())
    return false;
  assert(reduced);

  PPL_DIRTY_TEMP_COEFFICIENT(inf1_n);
  PPL_DIRTY_TEMP_COEFFICIENT(inf1_d);
  PPL_DIRTY_TEMP_COEFFICIENT(inf2_n);
  PPL_DIRTY_TEMP_COEFFICIENT(inf2_d);
  bool minimum1;
  bool minimum2;
  Generator pnt1(point());
  Generator pnt2(point());
  bool r1 = d1.minimize(expr, inf1_n, inf1_d, minimum1, pnt1);
  bool r2 = d2.minimize(expr, inf2_n, inf2_d, minimum2, pnt2);
  // If neither is bounded from below, return false.
  if (!r1 && !r2)
    return false;
  // If only d2 is bounded from below, then use the values for d2.
  if (!r1) {
    inf_n = inf2_n;
    inf_d = inf2_d;
    minimum = minimum2;
    pnt = pnt2;
    return true;
  }
  // If only d1 is bounded from below, then use the values for d1.
  if (!r2) {
    inf_n = inf1_n;
    inf_d = inf1_d;
    minimum = minimum1;
    pnt = pnt1;
    return true;
  }
  // If both d1 and d2 are bounded from below, then use the minimum values.
  if (inf2_d * inf1_n <= inf1_d * inf2_n) {
    inf_n = inf1_n;
    inf_d = inf1_d;
    minimum = minimum1;
    pnt = pnt1;
  }
  else {
    inf_n = inf2_n;
    inf_d = inf2_d;
    minimum = minimum2;
    pnt = pnt2;
  }
  return true;
 }

template <typename D1, typename D2, typename R>
inline bool
Partially_Reduced_Product<D1, D2, R>::OK() const {
  if (reduced) {
    Partially_Reduced_Product<D1, D2, R> pd1 = *this;
    Partially_Reduced_Product<D1, D2, R> pd2 = *this;
    /* Force pd1 reduction */
    pd1.clear_reduced_flag();
    pd1.reduce();
    if (pd1 != pd2)
      return false;
  }
  return d1.OK() && d2.OK();
}

template <typename D1, typename D2, typename R>
bool
Partially_Reduced_Product<D1, D2, R>::ascii_load(std::istream& s) {
  const char yes = '+';
  const char no = '-';
  std::string str;
  if (!(s >> str) || str != "Partially_Reduced_Product")
    return false;
  if (!(s >> str)
      || (str[0] != yes && str[0] != no)
      || str.substr(1) != "reduced")
    return false;
  reduced = (str[0] == yes);
  return ((s >> str) && str == "Domain"
          && (s >> str) && str == "1:"
	  && d1.ascii_load(s)
	  && (s >> str) && str == "Domain"
	  && (s >> str) && str == "2:"
	  && d2.ascii_load(s));
}

template <typename D1, typename D2>
void Smash_Reduction<D1, D2>::product_reduce(D1& d1, D2& d2) {
  if (d2.is_empty()) {
    if (!d1.is_empty()) {
      D1 new_d1(d1.space_dimension(), EMPTY);
      std::swap(d1, new_d1);
    }
  }
  else if (d1.is_empty()) {
    D2 new_d2(d2.space_dimension(), EMPTY);
    std::swap(d2, new_d2);
  }
}

template <typename D1, typename D2>
void Constraints_Reduction<D1, D2>::product_reduce(D1& d1, D2& d2) {
  if (d1.is_empty() || d2.is_empty()) {
    // If one of the components is empty, do the smash reduction and return.
    Parma_Polyhedra_Library::Smash_Reduction<D1, D2> sr;
    sr.product_reduce(d1, d2);
    return;
  }
  else {
    d1.refine_with_constraints(d2.minimized_constraints());
    d2.refine_with_constraints(d1.minimized_constraints());
  }
}

} // namespace Parma_Polyhedra_Library

/* Automatically generated from PPL source file ../src/Partially_Reduced_Product.defs.hh line 1592. */

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


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


namespace Parma_Polyhedra_Library {

template <typename PS>
class Determinate;

} // namespace Parma_Polyhedra_Library

/* 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 PS>
bool operator==(const Determinate<PS>& x, const Determinate<PS>& y);

/*! \brief
  Returns <CODE>true</CODE> if and only if
  \p x and \p y are different domain elements.

  \relates Determinate
*/
template <typename PS>
bool operator!=(const Determinate<PS>& x, const Determinate<PS>& y);

namespace IO_Operators {

//! Output operator.
/*! \relates Parma_Polyhedra_Library::Determinate */
template <typename PS>
std::ostream&
operator<<(std::ostream&, const Determinate<PS>&);

} // namespace IO_Operators

} // namespace Parma_Polyhedra_Library

//! Wraps a PPL class into a determinate constraint system interface.
/*! \ingroup PPL_CXX_interface */
template <typename PS>
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 PS& 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 PS& 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;

  /*!
    Returns <CODE>true</CODE> if and only if this domain
    has a nontrivial weakening operator.
  */
  static bool has_nontrivial_weakening();

  //! 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);

  //! Assigns to \p *this the result of weakening \p *this with \p y.
  void weakening_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.
  PS& 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 // defined(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 PS, producing the corresponding function object taking
    arguments of type Determinate<PS>.

    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(PS& x, const PS& 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 // defined(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 // defined(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.
    PS 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 PS& 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==<PS>(const Determinate<PS>& x, const Determinate<PS>& y);
  friend bool
  operator!=<PS>(const Determinate<PS>& x, const Determinate<PS>& y);
};


namespace std {

//! Specializes <CODE>std::swap</CODE>.
/*! \relates Parma_Polyhedra_Library::Determinate */
template <typename PS>
void swap(Parma_Polyhedra_Library::Determinate<PS>& x,
	  Parma_Polyhedra_Library::Determinate<PS>& 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 PS>
inline
Determinate<PS>::Rep::Rep(dimension_type num_dimensions,
			  Degenerate_Element kind)
  : references(0), ph(num_dimensions, kind) {
}

template <typename PS>
inline
Determinate<PS>::Rep::Rep(const PS& p)
  : references(0), ph(p) {
}

template <typename PS>
inline
Determinate<PS>::Rep::Rep(const Constraint_System& cs)
  : references(0), ph(cs) {
}

template <typename PS>
inline
Determinate<PS>::Rep::Rep(const Congruence_System& cgs)
  : references(0), ph(cgs) {
}

template <typename PS>
inline
Determinate<PS>::Rep::~Rep() {
  assert(references == 0);
}

template <typename PS>
inline void
Determinate<PS>::Rep::new_reference() const {
  ++references;
}

template <typename PS>
inline bool
Determinate<PS>::Rep::del_reference() const {
  return --references == 0;
}

template <typename PS>
inline bool
Determinate<PS>::Rep::is_shared() const {
  return references > 1;
}

template <typename PS>
inline memory_size_type
Determinate<PS>::Rep::external_memory_in_bytes() const {
  return ph.external_memory_in_bytes();
}

template <typename PS>
inline memory_size_type
Determinate<PS>::Rep::total_memory_in_bytes() const {
  return sizeof(*this) + external_memory_in_bytes();
}

template <typename PS>
inline
Determinate<PS>::Determinate(const PS& ph)
  : prep(new Rep(ph)) {
  prep->new_reference();
}

template <typename PS>
inline
Determinate<PS>::Determinate(const Constraint_System& cs)
  : prep(new Rep(cs)) {
  prep->new_reference();
}

template <typename PS>
inline
Determinate<PS>::Determinate(const Congruence_System& cgs)
  : prep(new Rep(cgs)) {
  prep->new_reference();
}

template <typename PS>
inline
Determinate<PS>::Determinate(const Determinate& y)
  : prep(y.prep) {
  prep->new_reference();
}

template <typename PS>
inline
Determinate<PS>::~Determinate() {
  if (prep->del_reference())
    delete prep;
}

template <typename PS>
inline Determinate<PS>&
Determinate<PS>::operator=(const Determinate& y) {
  y.prep->new_reference();
  if (prep->del_reference())
    delete prep;
  prep = y.prep;
  return *this;
}

template <typename PS>
inline void
Determinate<PS>::swap(Determinate& y) {
  std::swap(prep, y.prep);
}

template <typename PS>
inline void
Determinate<PS>::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 PS>
inline const PS&
Determinate<PS>::element() const {
  return prep->ph;
}

template <typename PS>
inline PS&
Determinate<PS>::element() {
  mutate();
  return prep->ph;
}

template <typename PS>
inline void
Determinate<PS>::upper_bound_assign(const Determinate& y) {
  element().upper_bound_assign(y.element());
}

template <typename PS>
inline void
Determinate<PS>::meet_assign(const Determinate& y) {
  element().intersection_assign(y.element());
}

template <typename PS>
inline bool
Determinate<PS>::has_nontrivial_weakening() {
  // FIXME: the following should be turned into a query to PS.  This
  // can be postponed until the time the ask-and-tell construction is
  // revived.
  return false;
}

template <typename PS>
inline void
Determinate<PS>::weakening_assign(const Determinate& y) {
  // FIXME: the following should be turned into a proper
  // implementation.  This can be postponed until the time the
  // ask-and-tell construction is revived.
  element().difference_assign(y.element());
}

template <typename PS>
inline void
Determinate<PS>::concatenate_assign(const Determinate& y) {
  element().concatenate_assign(y.element());
}

template <typename PS>
inline bool
Determinate<PS>::definitely_entails(const Determinate& y) const {
  return prep == y.prep || y.prep->ph.contains(prep->ph);
}

template <typename PS>
inline bool
Determinate<PS>::is_definitely_equivalent_to(const Determinate& y) const {
  return prep == y.prep || prep->ph == y.prep->ph;
}

template <typename PS>
inline bool
Determinate<PS>::is_top() const {
  return prep->ph.is_universe();
}

template <typename PS>
inline bool
Determinate<PS>::is_bottom() const {
  return prep->ph.is_empty();
}

template <typename PS>
inline memory_size_type
Determinate<PS>::external_memory_in_bytes() const {
  return prep->total_memory_in_bytes();
}

template <typename PS>
inline memory_size_type
Determinate<PS>::total_memory_in_bytes() const {
  return sizeof(*this) + external_memory_in_bytes();
}

template <typename PS>
inline bool
Determinate<PS>::OK() const {
  return prep->ph.OK();
}

namespace IO_Operators {

/*! \relates Parma_Polyhedra_Library::Determinate */
template <typename PS>
inline std::ostream&
operator<<(std::ostream& s, const Determinate<PS>& x) {
  s << x.element();
  return s;
}

} // namespace IO_Operators

/*! \relates Determinate */
template <typename PS>
inline bool
operator==(const Determinate<PS>& x, const Determinate<PS>& y) {
  return x.prep == y.prep || x.prep->ph == y.prep->ph;
}

/*! \relates Determinate */
template <typename PS>
inline bool
operator!=(const Determinate<PS>& x, const Determinate<PS>& y) {
  return x.prep != y.prep && x.prep->ph != y.prep->ph;
}

template <typename PS>
template <typename Binary_Operator_Assign>
inline
Determinate<PS>::Binary_Operator_Assign_Lifter<Binary_Operator_Assign>::
Binary_Operator_Assign_Lifter(Binary_Operator_Assign op_assign)
  : op_assign_(op_assign) {
}

template <typename PS>
template <typename Binary_Operator_Assign>
inline void
Determinate<PS>::Binary_Operator_Assign_Lifter<Binary_Operator_Assign>::
operator()(Determinate& x, const Determinate& y) const {
  op_assign_(x.element(), y.element());
}

template <typename PS>
template <typename Binary_Operator_Assign>
inline
Determinate<PS>::Binary_Operator_Assign_Lifter<Binary_Operator_Assign>
Determinate<PS>::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 PS>
inline void
swap(Parma_Polyhedra_Library::Determinate<PS>& x,
     Parma_Polyhedra_Library::Determinate<PS>& y) {
  x.swap(y);
}

} // namespace std

/* Automatically generated from PPL source file ../src/Determinate.defs.hh line 324. */

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


/* 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/iterator_to_const.defs.hh line 1. */
/* iterator_to_const and const_iterator_to_const class declarations.
*/


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


namespace Parma_Polyhedra_Library {

template <typename Container>
class iterator_to_const;

template <typename Container>
class const_iterator_to_const;

} // namespace Parma_Polyhedra_Library

/* Automatically generated from PPL source file ../src/iterator_to_const.defs.hh line 28. */
//#include "Ask_Tell.types.hh"
#include <iterator>

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! An iterator on a sequence of read-only objects.
/*! \ingroup PPL_CXX_interface
  This template class implements a bidirectional <EM>read-only</EM>
  iterator on the sequence of objects <CODE>Container</CODE>.
  By using this iterator class it is not possible to modify the objects
  contained in <CODE>Container</CODE>; rather, object modification has
  to be implemented by object replacement, i.e., by using the methods
  provided by <CODE>Container</CODE> to remove/insert objects.
  Such a policy (a modifiable container of read-only objects) allows
  for a reliable enforcement of invariants (such as sortedness of the
  objects in the sequence).

  \note
  For any developers' need, suitable friend declarations allow for
  accessing the low-level iterators on the sequence of objects.
*/
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename Container>
class Parma_Polyhedra_Library::iterator_to_const {
private:
  //! The type of the underlying mutable iterator.
  typedef typename Container::iterator Base;

  //! A shortcut for naming the const_iterator traits.
  typedef typename
  std::iterator_traits<typename Container::const_iterator> Traits;

  //! A (mutable) iterator on the sequence of elements.
  Base base;

  //! Constructs from the lower-level iterator.
  iterator_to_const(const Base& b);

  friend class const_iterator_to_const<Container>;
  template <typename T> friend class Powerset;
  //template <typename T> friend class Ask_Tell;

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.
  iterator_to_const();

  //! Copy constructor.
  iterator_to_const(const iterator_to_const& y);

  //! Dereference operator.
  reference operator*() const;

  //! Indirect access operator.
  pointer operator->() const;

  //! Prefix increment operator.
  iterator_to_const& operator++();

  //! Postfix increment operator.
  iterator_to_const operator++(int);

  //! Prefix decrement operator.
  iterator_to_const& operator--();

  //! Postfix decrement operator.
  iterator_to_const operator--(int);

  /*! \brief
    Returns <CODE>true</CODE> if and only if
    \p *this and \p y are identical.
  */
  bool operator==(const iterator_to_const& y) const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if
    \p *this and \p y are different.
  */
  bool operator!=(const iterator_to_const& y) const;
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! A %const_iterator on a sequence of read-only objects.
/*! \ingroup PPL_CXX_interface
  This class, besides implementing a read-only bidirectional iterator
  on a read-only sequence of objects, ensures interoperability
  with template class iterator_to_const.
*/
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename Container>
class Parma_Polyhedra_Library::const_iterator_to_const {
private:
  //! The type of the underlying %const_iterator.
  typedef typename Container::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.
  const_iterator_to_const(const Base& b);

  friend class iterator_to_const<Container>;
  template <typename T> friend class Powerset;
  //template <typename T> friend class Ask_Tell;

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.
  const_iterator_to_const();

  //! Copy constructor.
  const_iterator_to_const(const const_iterator_to_const& y);

  //! Constructs from the corresponding non-const iterator.
  const_iterator_to_const(const iterator_to_const<Container>& y);

  //! Dereference operator.
  reference operator*() const;

  //! Indirect member selector.
  pointer operator->() const;

  //! Prefix increment operator.
  const_iterator_to_const& operator++();

  //! Postfix increment operator.
  const_iterator_to_const operator++(int);

  //! Prefix decrement operator.
  const_iterator_to_const& operator--();

  //! Postfix decrement operator.
  const_iterator_to_const operator--(int);

  /*! \brief
    Returns <CODE>true</CODE> if and only if
    \p *this and \p y are identical.
  */
  bool operator==(const const_iterator_to_const& y) const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if
    \p *this and \p y are different.
  */
  bool operator!=(const const_iterator_to_const& 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 const_iterator_to_const
*/
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename Container>
bool
operator==(const iterator_to_const<Container>& x,
	   const const_iterator_to_const<Container>& 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 const_iterator_to_const
*/
#endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename Container>
bool
operator!=(const iterator_to_const<Container>& x,
	   const const_iterator_to_const<Container>& y);

} // namespace Parma_Polyhedra_Library

/* Automatically generated from PPL source file ../src/iterator_to_const.inlines.hh line 1. */
/* iterator_to_const and const_iterator_to_const class implementations:
   inline functions.
*/


namespace Parma_Polyhedra_Library {

template <typename Container>
inline
iterator_to_const<Container>::iterator_to_const()
  : base() {
}

template <typename Container>
inline
iterator_to_const<Container>::iterator_to_const(const iterator_to_const& y)
  : base(y.base) {
}

template <typename Container>
inline
iterator_to_const<Container>::iterator_to_const(const Base& b)
  : base(b) {
}

template <typename Container>
inline typename iterator_to_const<Container>::reference
iterator_to_const<Container>::operator*() const {
  return *base;
}

template <typename Container>
inline typename iterator_to_const<Container>::pointer
iterator_to_const<Container>::operator->() const {
  return &*base;
}

template <typename Container>
inline iterator_to_const<Container>&
iterator_to_const<Container>::operator++() {
  ++base;
  return *this;
}

template <typename Container>
inline iterator_to_const<Container>
iterator_to_const<Container>::operator++(int) {
  iterator_to_const tmp = *this;
  operator++();
  return tmp;
}

template <typename Container>
inline iterator_to_const<Container>&
iterator_to_const<Container>::operator--() {
  --base;
  return *this;
}

template <typename Container>
inline iterator_to_const<Container>
iterator_to_const<Container>::operator--(int) {
  iterator_to_const tmp = *this;
  operator--();
  return tmp;
}

template <typename Container>
inline bool
iterator_to_const<Container>::operator==(const iterator_to_const& y) const {
  return base == y.base;
}

template <typename Container>
inline bool
iterator_to_const<Container>::operator!=(const iterator_to_const& y) const {
  return !operator==(y);
}

template <typename Container>
inline
const_iterator_to_const<Container>::const_iterator_to_const()
  : base() {
}

template <typename Container>
inline
const_iterator_to_const<Container>
::const_iterator_to_const(const const_iterator_to_const& y)
  : base(y.base) {
}

template <typename Container>
inline
const_iterator_to_const<Container>::const_iterator_to_const(const Base& b)
  : base(b) {
}

template <typename Container>
inline typename const_iterator_to_const<Container>::reference
const_iterator_to_const<Container>::operator*() const {
  return *base;
}

template <typename Container>
inline typename const_iterator_to_const<Container>::pointer
const_iterator_to_const<Container>::operator->() const {
  return &*base;
}

template <typename Container>
inline const_iterator_to_const<Container>&
const_iterator_to_const<Container>::operator++() {
  ++base;
  return *this;
}

template <typename Container>
inline const_iterator_to_const<Container>
const_iterator_to_const<Container>::operator++(int) {
  const_iterator_to_const tmp = *this;
  operator++();
  return tmp;
}

template <typename Container>
inline const_iterator_to_const<Container>&
const_iterator_to_const<Container>::operator--() {
  --base;
  return *this;
}

template <typename Container>
inline const_iterator_to_const<Container>
const_iterator_to_const<Container>::operator--(int) {
  const_iterator_to_const tmp = *this;
  operator--();
  return tmp;
}

template <typename Container>
inline bool
const_iterator_to_const<Container>
::operator==(const const_iterator_to_const& y) const {
  return base == y.base;
}

template <typename Container>
inline bool
const_iterator_to_const<Container>
::operator!=(const const_iterator_to_const& y) const {
  return !operator==(y);
}

template <typename Container>
inline
const_iterator_to_const<Container>
::const_iterator_to_const(const iterator_to_const<Container>& y)
  : base(y.base) {
}

/*! \relates const_iterator_to_const */
template <typename Container>
inline bool
operator==(const iterator_to_const<Container>& x,
	   const const_iterator_to_const<Container>& y) {
  return const_iterator_to_const<Container>(x).operator==(y);
}

/*! \relates const_iterator_to_const */
template <typename Container>
inline bool
operator!=(const iterator_to_const<Container>& x,
	   const const_iterator_to_const<Container>& y) {
  return !(x == y);
}

} // namespace Parma_Polyhedra_Library

/* Automatically generated from PPL source file ../src/iterator_to_const.defs.hh line 221. */

/* Automatically generated from PPL source file ../src/Powerset.defs.hh line 29. */
#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 template 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 Object
  //@{

  /*! \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 Object

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;

  /*! \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 iterator_to_const<Sequence> iterator;

  //! A bidirectional %const_iterator on the disjuncts of a Powerset element.
  typedef const_iterator_to_const<Sequence> 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;

  /*! \brief
    Returns <CODE>true</CODE> if and only if there are no disjuncts in
    \p *this.
  */
  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 Object
  //@{

  //! 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);

  /*! \brief
    Assigns to \p *this the least upper bound of \p *this and \p y
    and returns \c true.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are dimension-incompatible.
  */
  bool upper_bound_assign_if_exact(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.
    If \p *this is reduced before an invocation of this method,
    it will be reduced upon successful return from the method.
  */
  iterator add_non_bottom_disjunct_preserve_reduction(const D& d,
						      iterator first,
						      iterator last);

  /*! \brief
    Adds to \p *this the disjunct \p d, assuming \p d is not the
    bottom element and preserving Omega-reduction.

    If \p *this is reduced before an invocation of this method,
    it will be reduced upon successful return from the method.
  */
  void add_non_bottom_disjunct_preserve_reduction(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);
};

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 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(false) {
  sequence.push_back(d);
  assert(OK());
}

template <typename D>
inline
Powerset<D>::~Powerset() {
}

template <typename D>
inline void
Powerset<D>::add_non_bottom_disjunct_preserve_reduction(const D& d) {
  // !d.is_bottom() is asserted by the callee.
  add_non_bottom_disjunct_preserve_reduction(d, begin(), end());
}

template <typename D>
inline void
Powerset<D>::add_disjunct(const D& d) {
  sequence.push_back(d);
  reduced = false;
}

/*! \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 bool
Powerset<D>::upper_bound_assign_if_exact(const Powerset& y) {
  least_upper_bound_assign(y);
  return true;
}

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.
*/


/* Automatically generated from PPL source file ../src/Powerset.templates.hh line 27. */
#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_preserve_reduction(const D& d,
							iterator first,
							iterator last) {
  assert(!d.is_bottom());
  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);
  assert(OK());
  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;
  assert(OK());
}

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_preserve_reduction(*i,
							   old_begin,
							   old_end);
  assert(OK());
}

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 453. */

/* Automatically generated from PPL source file ../src/Pointset_Powerset.defs.hh line 43. */
#include <iosfwd>
#include <list>
#include <map>

//! The powerset construction instantiated on PPL pointset domains.
/*! \ingroup PPL_CXX_interface */
/*!
  \warning
  At present, the supported instantiations for the
  disjunct domain template \p PS are the simple pointset domains:
  <CODE>C_Polyhedron</CODE>,
  <CODE>NNC_Polyhedron</CODE>,
  <CODE>Grid</CODE>,
  <CODE>Octagonal_Shape<T></CODE>,
  <CODE>BD_Shape<T></CODE>,
  <CODE>Box<T></CODE>.
*/
template <typename PS>
class Parma_Polyhedra_Library::Pointset_Powerset
  : public Parma_Polyhedra_Library::Powerset
<Parma_Polyhedra_Library::Determinate<PS> > {
public:
  typedef PS element_type;

private:
  typedef Determinate<PS> CS;
  typedef Powerset<CS> Base;

public:
  //! Returns the maximum space dimension a Pointset_Powerset<PS> can handle.
  static dimension_type max_space_dimension();

  //! \name Constructors
  //@{

  //! Builds a universe (top) or empty (bottom) Pointset_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
  Pointset_Powerset(dimension_type num_dimensions = 0,
		    Degenerate_Element kind = UNIVERSE);

  //! Ordinary copy-constructor.
  /*!
    The complexity argument is ignored.
  */
  Pointset_Powerset(const Pointset_Powerset& y,
                    Complexity_Class complexity = ANY_COMPLEXITY);

  /*! \brief
    Conversion constructor: the type <CODE>QH</CODE> of the disjuncts
    in the source powerset is different from <CODE>PS</CODE>.

    \param y
    The powerset to be used to build the new powerset.

    \param complexity
    The maximal complexity of any algorithms used.
  */
  template <typename QH>
  explicit Pointset_Powerset(const Pointset_Powerset<QH>& y,
                             Complexity_Class complexity = ANY_COMPLEXITY);

  /*! \brief
    Creates a Pointset_Powerset from a product
    This will be created as a single disjunct of type PS that
    approximates the product.
  */
   template <typename QH1, typename QH2, typename R>
   explicit
     Pointset_Powerset(const Partially_Reduced_Product<QH1, QH2, R>& prp,
                       Complexity_Class complexity = ANY_COMPLEXITY);

  /*! \brief
    Creates a Pointset_Powerset with a single disjunct approximating
    the system of constraints \p cs.
  */
  explicit Pointset_Powerset(const Constraint_System& cs);

  /*! \brief
    Creates a Pointset_Powerset with a single disjunct approximating
    the system of congruences \p cgs.
  */
  explicit Pointset_Powerset(const Congruence_System& cgs);


  //! Builds a pointset_powerset out of a closed polyhedron.
  /*!
    Builds a powerset that is either empty (if the polyhedron is found
    to be empty) or contains a single disjunct approximating the
    polyhedron; this must only use algorithms that do not exceed the
    specified complexity.  The powerset inherits the space dimension
    of the polyhedron.

    \param ph
    The closed polyhedron to be used to build the powerset.

    \param complexity
    The maximal complexity of any algorithms used.

    \exception std::length_error
    Thrown if the space dimension of \p ph exceeds the maximum
    allowed space dimension.
  */
  explicit Pointset_Powerset(const C_Polyhedron& ph,
                             Complexity_Class complexity = ANY_COMPLEXITY);

  //! Builds a pointset_powerset out of an nnc polyhedron.
  /*!
    Builds a powerset that is either empty (if the polyhedron is found
    to be empty) or contains a single disjunct approximating the
    polyhedron; this must only use algorithms that do not exceed the
    specified complexity.  The powerset inherits the space dimension
    of the polyhedron.

    \param ph
    The closed polyhedron to be used to build the powerset.

    \param complexity
    The maximal complexity of any algorithms used.

    \exception std::length_error
    Thrown if the space dimension of \p ph exceeds the maximum
    allowed space dimension.
  */
  explicit Pointset_Powerset(const NNC_Polyhedron& ph,
                             Complexity_Class complexity = ANY_COMPLEXITY);


  //! Builds a pointset_powerset out of a grid.
  /*!
    If the grid is nonempty, builds a powerset containing a single
    disjunct approximating the grid. Builds the empty powerset
    otherwise. The powerset inherits the space dimension of the grid.

    \param gr
    The grid to be used to build the powerset.

    \param complexity
    This argument is ignored.

    \exception std::length_error
    Thrown if the space dimension of \p gr exceeds the maximum
    allowed space dimension.
  */
  explicit Pointset_Powerset(const Grid& gr,
                             Complexity_Class complexity = ANY_COMPLEXITY);

  //! Builds a pointset_powerset out of an octagonal shape.
  /*!
    If the octagonal shape is nonempty, builds a powerset
    containing a single disjunct approximating the octagonal
    shape. Builds the empty powerset otherwise. The powerset
    inherits the space dimension of the octagonal shape.

    \param os
    The octagonal shape to be used to build the powerset.

    \param complexity
    This argument is ignored.

    \exception std::length_error
    Thrown if the space dimension of \p os exceeds the maximum
    allowed space dimension.
  */
  template <typename T>
  explicit Pointset_Powerset(const Octagonal_Shape<T>& os,
                             Complexity_Class complexity = ANY_COMPLEXITY);

  //! Builds a pointset_powerset out of a bd shape.
  /*!
    If the bd shape is nonempty, builds a powerset containing a
    single disjunct approximating the bd shape. Builds the empty
    powerset otherwise.  The powerset inherits the space dimension
    of the bd shape.

    \param bds
    The bd shape to be used to build the powerset.

    \param complexity
    This argument is ignored.

    \exception std::length_error
    Thrown if the space dimension of \p bdss exceeds the maximum
    allowed space dimension.
  */
  template <typename T>
  explicit Pointset_Powerset(const BD_Shape<T>& bds,
                             Complexity_Class complexity = ANY_COMPLEXITY);

  //! Builds a pointset_powerset out of a box.
  /*!
    If the box is nonempty, builds a powerset containing a single
    disjunct approximating the box. Builds the empty powerset
    otherwise.  The powerset inherits the space dimension of the box.

    \param box
    The box to be used to build the powerset.

    \param complexity
    This argument is ignored.

    \exception std::length_error
    Thrown if the space dimension of \p box exceeds the maximum
    allowed space dimension.
  */
  template <typename Interval>
  explicit Pointset_Powerset(const Box<Interval>& box,
                             Complexity_Class complexity = ANY_COMPLEXITY);

  //@} // Constructors and Destructor

  //! \name Member Functions that Do Not Modify the Pointset_Powerset
  //@{

  //! Returns the dimension of the vector space enclosing \p *this.
  dimension_type space_dimension() const;

  //! Returns the dimension of the vector space enclosing \p *this.
  dimension_type affine_dimension() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this is
    an empty powerset.
  */
  bool is_empty() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this
    is the top element of the powerser lattice.
  */
  bool is_universe() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if all the disjuncts
    in \p *this are topologically closed.
  */
  bool is_topologically_closed() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if all elements in \p *this
    are bounded.
  */
  bool is_bounded() 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 Pointset_Powerset& y) const;

  //! Returns <CODE>true</CODE> if and only if \p *this is discrete.
  bool is_discrete() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p var is constrained in
    \p *this.

    \exception std::invalid_argument
    Thrown if \p var is not a space dimension of \p *this.

    \note
    A variable is constrained if there exists a non-redundant disjunct
    that is constraining the variable: this definition relies on the
    powerset lattice structure and may be somewhat different from the
    geometric intuition.
    For instance, variable \f$x\f$ is constrained in the powerset
    \f[
      \mathit{ps} = \bigl\{ \{ x \geq 0 \}, \{ x \leq 0 \} \bigr\},
    \f]
    even though \f$\mathit{ps}\f$ is geometrically equal to the
    whole vector space.
  */
  bool constrains(Variable var) 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 g
    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 g are left untouched.
  */
  bool maximize(const Linear_Expression& expr,
		Coefficient& sup_n, Coefficient& sup_d, bool& maximum,
		Generator& g) 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 g
    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 g are left untouched.
  */
  bool minimize(const Linear_Expression& expr,
		Coefficient& inf_n, Coefficient& inf_d, bool& minimum,
		Generator& g) 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 dimension-incompatible.

    \warning
    This may be <EM>really</EM> expensive!
  */
  bool geometrically_covers(const Pointset_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 dimension-incompatible.

    \warning
    This may be <EM>really</EM> expensive!
  */
  bool geometrically_equals(const Pointset_Powerset& y) const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if each disjunct
      of \p y is contained in a disjunct of \p *this.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are topology-incompatible or
    dimension-incompatible.
  */
  bool contains(const Pointset_Powerset& y) const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if each disjunct
      of \p y is strictly contained in a disjunct of \p *this.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are topology-incompatible or
    dimension-incompatible.
  */
  bool strictly_contains(const Pointset_Powerset& y) const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this
    contains at least one integer point.
  */
  bool contains_integer_point() const;

  /*! \brief
    Returns the relations holding between the powerset \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 powerset \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 the relations holding between the powerset \p *this
    and the congruence \p c.

    \exception std::invalid_argument
    Thrown if \p *this and congruence \p c are dimension-incompatible.
  */
  Poly_Con_Relation relation_with(const Congruence& cg) 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
    Returns a 32-bit hash code for \p *this.

    If \p x and \p y are such that <CODE>x == y</CODE>,
    then <CODE>x.hash_code() == y.hash_code()</CODE>.
  */
  int32_t hash_code() const;

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

  //@} // Member Functions that Do Not Modify the Pointset_Powerset

  //! \name Space Dimension Preserving Member Functions that May Modify the Pointset_Powerset
  //@{

  //! 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 PS& 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);

  /*! \brief
    Use the constraint \p c to refine \p *this.

    \param c
    The constraint to be used for refinement.

    \exception std::invalid_argument
    Thrown if \p *this and \p c are dimension-incompatible.
  */
  void refine_with_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.

    \deprecated
    See \ref A_Note_on_the_Implementation_of_the_Operators.
  */
  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
    Use the constraints in \p cs to refine \p *this.

    \param  cs
     The constraints to be used for refinement.

     \exception std::invalid_argument
     Thrown if \p *this and \p cs are dimension-incompatible.
  */
  void refine_with_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.

    \deprecated
    See \ref A_Note_on_the_Implementation_of_the_Operators.
  */
  bool add_constraints_and_minimize(const Constraint_System& cs);

  //! Intersects \p *this with congruence \p c.
  /*!
    \exception std::invalid_argument
    Thrown if \p *this and congruence \p c are topology-incompatible
    or dimension-incompatible.
  */
  void add_congruence(const Congruence& c);

  /*! \brief
    Use the congruence \p cg to refine \p *this.

    \param cg
    The congruence to be used for refinement.

    \exception std::invalid_argument
    Thrown if \p *this and \p cg are dimension-incompatible.
  */
  void refine_with_congruence(const Congruence& cg);

  //! Intersects \p *this with the congruence \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.

    \deprecated
    See \ref A_Note_on_the_Implementation_of_the_Operators.
  */
  bool add_congruence_and_minimize(const Congruence& c);

  //! Intersects \p *this with the congruences in \p cgs.
  /*!
    \param cgs
    The congruences to intersect with.

    \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
    Use the congruences in \p cgs to refine \p *this.

    \param  cgs
    The congruences to be used for refinement.

    \exception std::invalid_argument
    Thrown if \p *this and \p cgs are dimension-incompatible.
  */
  void refine_with_congruences(const Congruence_System& cgs);

  /*! \brief
    Intersects \p *this with the congruences in \p cs,
    minimizing the result.

    \return
    <CODE>false</CODE> if and only if the result is empty.

    \param cs
    The congruences to intersect with.

    \exception std::invalid_argument
    Thrown if \p *this and \p cs are topology-incompatible or
    dimension-incompatible.

    \deprecated
    See \ref A_Note_on_the_Implementation_of_the_Operators.
  */
  bool add_congruences_and_minimize(const Congruence_System& cs);

  /*! \brief
    Computes the \ref Cylindrification "cylindrification" of \p *this with
    respect to space dimension \p var, assigning the result to \p *this.

    \param var
    The space dimension that will be unconstrained.

    \exception std::invalid_argument
    Thrown if \p var is not a space dimension of \p *this.
  */
  void unconstrain(Variable var);

  /*! \brief
    Computes the \ref Cylindrification "cylindrification" of \p *this with
    respect to the set of space dimensions \p to_be_unconstrained,
    assigning the result to \p *this.

    \param to_be_unconstrained
    The set of space dimension that will be unconstrained.

    \exception std::invalid_argument
    Thrown if \p *this is dimension-incompatible with one of the
    Variable objects contained in \p to_be_removed.
  */
  void unconstrain(const Variables_Set& to_be_unconstrained);

  //! Assigns to \p *this its topological closure.
  void topological_closure_assign();

  //! Assigns to \p *this the intersection of \p *this and \p y.
  /*!
    The result is obtained by intersecting each disjunct in \p *this
    with each disjunct in \p y and collecting all these intersections.
  */
  void intersection_assign(const Pointset_Powerset& y);

  //! Assigns to \p *this the intersection of \p *this and \p y.
  /*!
    The result is obtained by intersecting each disjunct in \p *this
    with each disjunct in \p y, minimizing the result
    and collecting all these intersections.

    \return
    <CODE>false</CODE> if and only if the result is empty.

    \deprecated
    See \ref A_Note_on_the_Implementation_of_the_Operators.
  */
  bool intersection_assign_and_minimize(const Pointset_Powerset& y);

  /*! \brief
    Assigns to \p *this an (a smallest)
    over-approximation as a powerset of the disjunct domain of the
    set-theoretical difference of \p *this and \p y.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are dimension-incompatible.
  */
  void difference_assign(const Pointset_Powerset& y);

  /*! \brief
    Assigns to \p *this a \ref Powerset_Meet_Preserving_Simplification
    "meet-preserving simplification" of \p *this with respect to \p y.
    If \c false is returned, then the intersection is empty.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are topology-incompatible or
    dimension-incompatible.
  */
  bool simplify_using_context_assign(const Pointset_Powerset& 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.
  */
  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 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.
  */
  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,
				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,
			      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,
				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,
				   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.

    The result is obtained by computing the pairwise
    \ref Time_Elapse_Operator "time elapse" of each disjunct
    in \p *this with each disjunct in \p y.
  */
  void time_elapse_assign(const Pointset_Powerset& y);

  /*! \brief
    Assign to \p *this the result of (recursively) merging together
    the pairs of disjuncts whose upper-bound is the same as their
    set-theoretical union.

    On exit, for all the pairs \f$\cP\f$, \f$\cQ\f$ of different disjuncts
    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 powerset that <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 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 Pointset_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 computed in the previous iteration step.
    It <EM>must</EM> definitely entail \p *this;

    \param wf
    The widening function to be used on disjuncts.
    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 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 Pointset_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).
  */
  Pointset_Powerset& operator=(const Pointset_Powerset& y);

  /*! \brief
    Conversion assignment: the type <CODE>QH</CODE> of the disjuncts
    in the source powerset is different from <CODE>PS</CODE>
    (\p *this and \p y can be dimension-incompatible).
  */
  template <typename QH>
  Pointset_Powerset& operator=(const Pointset_Powerset<QH>& y);

  //! Swaps \p *this with \p y.
  void swap(Pointset_Powerset& y);

  /*! \brief
    Adds \p m new dimensions to the vector space containing \p *this
    and embeds each disjunct 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 disjuncts in \p *this in the new space.
  */
  void add_space_dimensions_and_project(dimension_type m);

  //! 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 disjunct
    in \p *this with each disjunct in \p y.
  */
  void concatenate_assign(const Pointset_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);

  //! 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 Expanding_One_Dimension_of_the_Vector_Space_to_Multiple_Dimensions
    "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 Folding_Multiple_Dimensions_of_the_Vector_Space_into_One_Dimension
    "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

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

  /*! \brief
    Loads from \p s an ASCII representation (as produced by
    ascii_dump(std::ostream&) const) and sets \p *this accordingly.
    Returns <CODE>true</CODE> if successful, <CODE>false</CODE> otherwise.
  */
  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 to_be_enlarged a
    \ref Powerset_Meet_Preserving_Simplification
    "powerset meet-preserving enlargement" of itself with respect to \p *this.
    If \c false is returned, then the intersection is empty.

    \note
    It is assumed that \p *this and \p to_be_enlarged are
    topology-compatible and dimension-compatible.
  */
  bool intersection_preserving_enlarge_element(PS& to_be_enlarged) const;

  /*! \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 Pointset_Powerset& y, Widening wf);

  //! Records in \p cert_ms the certificates for this set of disjuncts.
  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 dijsuncts
    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 template constructor
  // template <typename QH>
  // Pointset_Powerset(const Pointset_Powerset<QH>&),
  // but, apparently, this cannot be done.
  friend class Pointset_Powerset<NNC_Polyhedron>;
};

namespace Parma_Polyhedra_Library {

//! Partitions \p q with respect to \p p.
/*! \relates Pointset_Powerset
  Let \p p and \p q be two polyhedra.
  The function returns an object <CODE>r</CODE> of type
  <CODE>std::pair\<PS, Pointset_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 set-theoretical 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 PS>
std::pair<PS, Pointset_Powerset<NNC_Polyhedron> >
linear_partition(const PS& p, const PS& 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 Pointset_Powerset
*/
bool
check_containment(const NNC_Polyhedron& ph,
		  const Pointset_Powerset<NNC_Polyhedron>& ps);


/*! \brief
  Partitions the grid \p q with respect to grid \p p if and only if
  such a partition is finite.

  \relates Parma_Polyhedra_Library::Pointset_Powerset
  Let \p p and \p q be two grids.
  The function returns an object <CODE>r</CODE> of type
  <CODE>std::pair\<PS, Pointset_Powerset\<Grid\> \></CODE>
  such that
  - <CODE>r.first</CODE> is the intersection of \p p and \p q;
  - If there is a finite partition of \p q wrt \p p
    the Boolean <CODE>finite_partition</CODE> is set to true and
    <CODE>r.second</CODE> has the property that all its elements are
    pairwise disjoint and disjoint from \p p and the set-theoretical
    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).
  - Otherwise the Boolean <CODE>finite_partition</CODE> is set to false
    and the singleton set that contains \p q is stored in
    <CODE>r.second</CODE>r.
*/
std::pair<Grid, Pointset_Powerset<Grid> >
approximate_partition(const Grid& p, const Grid& q, bool& finite_partition);

/*! \brief
  Returns <CODE>true</CODE> if and only if the union of
  the grids \p ps contains the grid \p g.

  \relates Pointset_Powerset
*/
bool
check_containment(const Grid& ph,
		  const Pointset_Powerset<Grid>& ps);

/*! \brief
  Returns <CODE>true</CODE> if and only if the union of
  the objects in \p ps contains \p ph.

  \relates Pointset_Powerset
  \note
  It is assumed that the template parameter PS can be converted
  without precision loss into an NNC_Polyhedron; otherwise,
  an incorrect result might be obtained.
*/
template <typename PS>
bool
check_containment(const PS& ph, const Pointset_Powerset<PS>& ps);

// CHECKME: 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>
Pointset_Powerset<NNC_Polyhedron>
::Pointset_Powerset(const Pointset_Powerset<QH>& y,
                    Complexity_Class);

// Non-inline full specializations should be declared here
// so as to inhibit multiple instantiations of the generic template.
template <>
template <>
Pointset_Powerset<NNC_Polyhedron>
::Pointset_Powerset(const Pointset_Powerset<C_Polyhedron>& y,
                    Complexity_Class);

template <>
template <>
Pointset_Powerset<NNC_Polyhedron>
::Pointset_Powerset(const Pointset_Powerset<Grid>& y,
                    Complexity_Class);

template <>
template <>
Pointset_Powerset<C_Polyhedron>
::Pointset_Powerset(const Pointset_Powerset<NNC_Polyhedron>& y,
                    Complexity_Class);

template <>
void
Pointset_Powerset<NNC_Polyhedron>
::difference_assign(const Pointset_Powerset& y);

template <>
void
Pointset_Powerset<Grid>
::difference_assign(const Pointset_Powerset& y);

template <>
bool
Pointset_Powerset<NNC_Polyhedron>
::geometrically_covers(const Pointset_Powerset& y) const;

template <>
bool
Pointset_Powerset<Grid>
::geometrically_covers(const Pointset_Powerset& y) const;

} // namespace Parma_Polyhedra_Library


namespace std {

//! Specializes <CODE>std::swap</CODE>.
/*! \relates Parma_Polyhedra_Library::Pointset_Powerset */
template <typename PS>
void swap(Parma_Polyhedra_Library::Pointset_Powerset<PS>& x,
	  Parma_Polyhedra_Library::Pointset_Powerset<PS>& y);

} // namespace std

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


/* Automatically generated from PPL source file ../src/Pointset_Powerset.inlines.hh line 34. */
#include <algorithm>
#include <deque>

namespace Parma_Polyhedra_Library {

template <typename PS>
inline dimension_type
Pointset_Powerset<PS>::space_dimension() const {
  return space_dim;
}

template <typename PS>
inline dimension_type
Pointset_Powerset<PS>::max_space_dimension() {
  return PS::max_space_dimension();
}

template <typename PS>
inline
Pointset_Powerset<PS>::Pointset_Powerset(dimension_type num_dimensions,
					 Degenerate_Element kind)
  : Base(), space_dim(num_dimensions) {
  Pointset_Powerset& x = *this;
  if (kind == UNIVERSE)
    x.sequence.push_back(Determinate<PS>(PS(num_dimensions, kind)));
  assert(x.OK());
}

template <typename PS>
inline
Pointset_Powerset<PS>::Pointset_Powerset(const Pointset_Powerset& y,
                                         Complexity_Class)
  : Base(y), space_dim(y.space_dim) {
}

template <typename PS>
inline
Pointset_Powerset<PS>::Pointset_Powerset(const C_Polyhedron& ph,
                                         Complexity_Class complexity)
  : Base(), space_dim(ph.space_dimension()) {
  Pointset_Powerset& x = *this;
  if (complexity == ANY_COMPLEXITY) {
    if (ph.is_empty())
      return;
  }
  else
    x.reduced = false;
  x.sequence.push_back(Determinate<PS>(PS(ph, complexity)));
  x.reduced = false;
  assert(OK());
}

template <typename PS>
inline
Pointset_Powerset<PS>::Pointset_Powerset(const NNC_Polyhedron& ph,
                                         Complexity_Class complexity)
  : Base(), space_dim(ph.space_dimension()) {
  Pointset_Powerset& x = *this;
  if (complexity == ANY_COMPLEXITY) {
    if (ph.is_empty())
      return;
  }
  else
    x.reduced = false;
  x.sequence.push_back(Determinate<PS>(PS(ph, complexity)));
  assert(OK());
}

template <typename PS>
inline
Pointset_Powerset<PS>::Pointset_Powerset(const Grid& gr,
                                         Complexity_Class)
  : Base(), space_dim(gr.space_dimension()) {
  Pointset_Powerset& x = *this;
  if (!gr.is_empty()) {
    x.sequence.push_back(Determinate<PS>(PS(gr)));
  }
  assert(OK());
}

template <typename PS>
template <typename QH1, typename QH2, typename R>
inline
Pointset_Powerset<PS>
::Pointset_Powerset(const Partially_Reduced_Product<QH1, QH2, R>& prp,
                    Complexity_Class complexity)
  : Base(), space_dim(prp.space_dimension()) {
  Pointset_Powerset& x = *this;
  if (complexity == ANY_COMPLEXITY) {
    if (prp.is_empty())
      return;
  }
  else
    x.reduced = false;
  x.sequence.push_back(Determinate<PS>(PS(prp, complexity)));
  x.reduced = false;
  assert(OK());
}

template <typename PS>
template <typename Interval>
Pointset_Powerset<PS>::Pointset_Powerset(const Box<Interval>& box,
                                         Complexity_Class)
  : Base(), space_dim(box.space_dimension()) {
  Pointset_Powerset& x = *this;
  if (!box.is_empty())
    x.sequence.push_back(Determinate<PS>(PS(box)));
  assert(OK());
}

template <typename PS>
template <typename T>
Pointset_Powerset<PS>::Pointset_Powerset(const Octagonal_Shape<T>& os,
                                         Complexity_Class)
  : Base(), space_dim(os.space_dimension()) {
  Pointset_Powerset& x = *this;
  if (!os.is_empty())
    x.sequence.push_back(Determinate<PS>(PS(os)));
  assert(OK());
}

template <typename PS>
template <typename T>
Pointset_Powerset<PS>::Pointset_Powerset(const BD_Shape<T>& bds,
                                         Complexity_Class)
  : Base(), space_dim(bds.space_dimension()) {
  Pointset_Powerset& x = *this;
  if (!bds.is_empty())
    x.sequence.push_back(Determinate<PS>(PS(bds)));
  assert(OK());
}

template <typename PS>
inline
Pointset_Powerset<PS>::Pointset_Powerset(const Constraint_System& cs)
  : Base(Determinate<PS>(cs)), space_dim(cs.space_dimension()) {
  assert(OK());
}

template <typename PS>
inline
Pointset_Powerset<PS>::Pointset_Powerset(const Congruence_System& cgs)
  : Base(Determinate<PS>(cgs)), space_dim(cgs.space_dimension()) {
  assert(OK());
}

template <typename PS>
inline Pointset_Powerset<PS>&
Pointset_Powerset<PS>::operator=(const Pointset_Powerset& y) {
  Pointset_Powerset& x = *this;
  x.Base::operator=(y);
  x.space_dim = y.space_dim;
  return x;
}

template <typename PS>
inline void
Pointset_Powerset<PS>::swap(Pointset_Powerset& y) {
  Pointset_Powerset& x = *this;
  x.Base::swap(y);
  std::swap(x.space_dim, y.space_dim);
}

template <typename PS>
template <typename QH>
inline Pointset_Powerset<PS>&
Pointset_Powerset<PS>::operator=(const Pointset_Powerset<QH>& y) {
  Pointset_Powerset& x = *this;
  Pointset_Powerset<PS> pps(y);
  x.swap(pps);
  return x;
}

template <typename PS>
inline void
Pointset_Powerset<PS>::intersection_assign(const Pointset_Powerset& y) {
  Pointset_Powerset& x = *this;
  x.pairwise_apply_assign
    (y, CS::lift_op_assign(std::mem_fun_ref(&PS::intersection_assign)));
}

template <typename PS>
inline bool
Pointset_Powerset<PS>
::intersection_assign_and_minimize(const Pointset_Powerset& y) {
  intersection_assign(y);
  return !is_empty();
}

template <typename PS>
inline void
Pointset_Powerset<PS>::time_elapse_assign(const Pointset_Powerset& y) {
  Pointset_Powerset& x = *this;
  x.pairwise_apply_assign
    (y, CS::lift_op_assign(std::mem_fun_ref(&PS::time_elapse_assign)));
}

template <typename PS>
inline bool
Pointset_Powerset<PS>
::geometrically_covers(const Pointset_Powerset& y) const {
  // This code is only used when PS is an abstraction of NNC_Polyhedron.
  const Pointset_Powerset<NNC_Polyhedron> xx(*this);
  const Pointset_Powerset<NNC_Polyhedron> yy(y);
  return xx.geometrically_covers(yy);
}

template <typename PS>
inline bool
Pointset_Powerset<PS>
::geometrically_equals(const Pointset_Powerset& y) const {
  // This code is only used when PS is an abstraction of NNC_Polyhedron.
  const Pointset_Powerset<NNC_Polyhedron> xx(*this);
  const Pointset_Powerset<NNC_Polyhedron> yy(y);
  return xx.geometrically_covers(yy) && yy.geometrically_covers(xx);
}

template <>
inline bool
Pointset_Powerset<Grid>
::geometrically_equals(const Pointset_Powerset& y) const {
  const Pointset_Powerset& x = *this;
  return x.geometrically_covers(y) && y.geometrically_covers(x);
}

template <>
inline bool
Pointset_Powerset<NNC_Polyhedron>
::geometrically_equals(const Pointset_Powerset& y) const {
  const Pointset_Powerset& x = *this;
  return x.geometrically_covers(y) && y.geometrically_covers(x);
}

template <typename PS>
inline memory_size_type
Pointset_Powerset<PS>::external_memory_in_bytes() const {
  return Base::external_memory_in_bytes();
}

template <typename PS>
inline memory_size_type
Pointset_Powerset<PS>::total_memory_in_bytes() const {
  return sizeof(*this) + external_memory_in_bytes();
}

template <typename PS>
inline int32_t
Pointset_Powerset<PS>::hash_code() const {
  return space_dimension() & 0x7fffffff;
}

template <typename PS>
inline void
Pointset_Powerset<PS>
::difference_assign(const Pointset_Powerset& y) {
  // This code is only used when PS is an abstraction of NNC_Polyhedron.
  Pointset_Powerset<NNC_Polyhedron> nnc_this(*this);
  Pointset_Powerset<NNC_Polyhedron> nnc_y(y);
  nnc_this.difference_assign(nnc_y);
  *this = nnc_this;
}

/*! \relates Pointset_Powerset */
template <typename PS>
inline bool
check_containment(const PS& ph, const Pointset_Powerset<PS>& ps) {
  // This code is only used when PS is an abstraction of NNC_Polyhedron.
  const NNC_Polyhedron pph = NNC_Polyhedron(ph.constraints());
  const Pointset_Powerset<NNC_Polyhedron> pps(ps);
  return check_containment(pph, pps);
}

/*! \relates Pointset_Powerset */
template <>
inline bool
check_containment(const C_Polyhedron& ph,
		  const Pointset_Powerset<C_Polyhedron>& ps) {
  return check_containment(NNC_Polyhedron(ph),
			   Pointset_Powerset<NNC_Polyhedron>(ps));
}

} // namespace Parma_Polyhedra_Library


namespace std {

/*! \relates Parma_Polyhedra_Library::Pointset_Powerset */
template <typename PS>
inline void
swap(Parma_Polyhedra_Library::Pointset_Powerset<PS>& x,
     Parma_Polyhedra_Library::Pointset_Powerset<PS>& y) {
  x.swap(y);
}

} // namespace std

/* Automatically generated from PPL source file ../src/Pointset_Powerset.templates.hh line 1. */
/* Pointset_Powerset class implementation: non-inline template functions.
*/


/* Automatically generated from PPL source file ../src/Pointset_Powerset.templates.hh line 32. */
#include <algorithm>
#include <deque>
#include <string>
#include <iostream>
#include <sstream>
#include <stdexcept>

namespace Parma_Polyhedra_Library {

template <typename PS>
void
Pointset_Powerset<PS>::add_disjunct(const PS& ph) {
  Pointset_Powerset& x = *this;
  if (x.space_dimension() != ph.space_dimension()) {
    std::ostringstream s;
    s << "PPL::Pointset_Powerset<PS>::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<PS>(ph));
  x.reduced = false;
  assert(x.OK());
}

template <>
template <typename QH>
Pointset_Powerset<NNC_Polyhedron>
::Pointset_Powerset(const Pointset_Powerset<QH>& y,
                    Complexity_Class complexity)
  : Base(), space_dim(y.space_dimension()) {
  Pointset_Powerset& x = *this;
  for (typename Pointset_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(), complexity)));

  // FIXME: If the domain elements can be represented _exactly_ as NNC
  // polyhedra, then having x.reduced = y.reduced is correct. This is
  // the case if the domains are both linear and convex which holds
  // for all the currently supported instantiations except for
  // Grids; for this reason the Grid specialization has a
  // separate implementation.  For any non-linear or non-convex
  // domains (e.g., a domain of Intervals with restrictions or a
  // domain of circles) that may be supported in the future, the
  // assignment x.reduced = y.reduced will be a bug.
  x.reduced = y.reduced;

  assert(x.OK());
}

template <typename PS>
template <typename QH>
Pointset_Powerset<PS>
::Pointset_Powerset(const Pointset_Powerset<QH>& y,
                    Complexity_Class complexity)
  : Base(), space_dim(y.space_dimension()) {
  Pointset_Powerset& x = *this;
  for (typename Pointset_Powerset<QH>::const_iterator i = y.begin(),
	 y_end = y.end(); i != y_end; ++i)
    x.sequence.push_back(Determinate<PS>(PS(i->element(), complexity)));
  // Note: this might be non-reduced even when `y' is known to be
  // omega-reduced, because the constructor of PS may have made
  // different QH elements to become comparable.
  x.reduced = false;
  assert(x.OK());
}

template <typename PS>
void
Pointset_Powerset<PS>::concatenate_assign(const Pointset_Powerset& y) {
  Pointset_Powerset& x = *this;
  // Ensure omega-reduction here, since what follows has quadratic complexity.
  x.omega_reduce();
  y.omega_reduce();
  Pointset_Powerset<PS> 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!
      PS xph = xi->element();
      for (++xi; xi != x_end; ++xi)
	xph.upper_bound_assign(xi->element());
      const_iterator yi = y_begin;
      PS 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 PS>
void
Pointset_Powerset<PS>::add_constraint(const Constraint& c) {
  Pointset_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 PS>
bool
Pointset_Powerset<PS>::add_constraint_and_minimize(const Constraint& c) {
  Pointset_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 PS>
void
Pointset_Powerset<PS>::refine_with_constraint(const Constraint& c) {
  Pointset_Powerset& x = *this;
  for (Sequence_iterator si = x.sequence.begin(),
	 s_end = x.sequence.end(); si != s_end; ++si)
    si->element().refine_with_constraint(c);
  x.reduced = false;
  assert(x.OK());
}

template <typename PS>
void
Pointset_Powerset<PS>::add_constraints(const Constraint_System& cs) {
  Pointset_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 PS>
bool
Pointset_Powerset<PS>::
add_constraints_and_minimize(const Constraint_System& cs) {
  Pointset_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 PS>
void
Pointset_Powerset<PS>::refine_with_constraints(const Constraint_System& cs) {
  Pointset_Powerset& x = *this;
  for (Sequence_iterator si = x.sequence.begin(),
	 s_end = x.sequence.end(); si != s_end; ++si)
    si->element().refine_with_constraints(cs);
  x.reduced = false;
  assert(x.OK());
}

template <typename PS>
void
Pointset_Powerset<PS>::add_congruence(const Congruence& c) {
  Pointset_Powerset& x = *this;
  for (Sequence_iterator si = x.sequence.begin(),
	 s_end = x.sequence.end(); si != s_end; ++si)
    si->element().add_congruence(c);
  x.reduced = false;
  assert(x.OK());
}

template <typename PS>
void
Pointset_Powerset<PS>::refine_with_congruence(const Congruence& cg) {
  Pointset_Powerset& x = *this;
  for (Sequence_iterator si = x.sequence.begin(),
	 s_end = x.sequence.end(); si != s_end; ++si)
    si->element().refine_with_congruence(cg);
  x.reduced = false;
  assert(x.OK());
}

template <typename PS>
bool
Pointset_Powerset<PS>::add_congruence_and_minimize(const Congruence& c) {
  Pointset_Powerset& x = *this;
  for (Sequence_iterator si = x.sequence.begin(),
	 s_end = x.sequence.end(); si != s_end; )
    if (!si->element().add_congruence_and_minimize(c))
      si = x.sequence.erase(si);
    else {
      x.reduced = false;
      ++si;
    }
  assert(x.OK());
  return !x.empty();
}

template <typename PS>
void
Pointset_Powerset<PS>::add_congruences(const Congruence_System& cs) {
  Pointset_Powerset& x = *this;
  for (Sequence_iterator si = x.sequence.begin(),
	 s_end = x.sequence.end(); si != s_end; ++si)
    si->element().add_congruences(cs);
  x.reduced = false;
  assert(x.OK());
}

template <typename PS>
void
Pointset_Powerset<PS>::refine_with_congruences(const Congruence_System& cgs) {
  Pointset_Powerset& x = *this;
  for (Sequence_iterator si = x.sequence.begin(),
	 s_end = x.sequence.end(); si != s_end; ++si)
    si->element().refine_with_congruences(cgs);
  x.reduced = false;
  assert(x.OK());
}

template <typename PS>
bool
Pointset_Powerset<PS>::
add_congruences_and_minimize(const Congruence_System& cs) {
  Pointset_Powerset& x = *this;
  for (Sequence_iterator si = x.sequence.begin(),
	 s_end = x.sequence.end(); si != s_end; )
    if (!si->element().add_congruences_and_minimize(cs))
      si = x.sequence.erase(si);
    else {
      x.reduced = false;
      ++si;
    }
  assert(x.OK());
  return !x.empty();
}

template <typename PS>
void
Pointset_Powerset<PS>::unconstrain(const Variable var) {
  Pointset_Powerset& x = *this;
  for (Sequence_iterator si = x.sequence.begin(),
         s_end = x.sequence.end(); si != s_end; ++si) {
    si->element().unconstrain(var);
    x.reduced = false;
  }
  assert(x.OK());
}

template <typename PS>
void
Pointset_Powerset<PS>::unconstrain(const Variables_Set& to_be_unconstrained) {
  Pointset_Powerset& x = *this;
  for (Sequence_iterator si = x.sequence.begin(),
         s_end = x.sequence.end(); si != s_end; ++si) {
    si->element().unconstrain(to_be_unconstrained);
    x.reduced = false;
  }
  assert(x.OK());
}

template <typename PS>
void
Pointset_Powerset<PS>::add_space_dimensions_and_embed(dimension_type m) {
  Pointset_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 PS>
void
Pointset_Powerset<PS>::add_space_dimensions_and_project(dimension_type m) {
  Pointset_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 PS>
void
Pointset_Powerset<PS>::
remove_space_dimensions(const Variables_Set& to_be_removed) {
  Pointset_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 PS>
void
Pointset_Powerset<PS>::remove_higher_space_dimensions(dimension_type
						      new_dimension) {
  Pointset_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 PS>
template <typename Partial_Function>
void
Pointset_Powerset<PS>::map_space_dimensions(const Partial_Function& pfunc) {
  Pointset_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 PS>
void
Pointset_Powerset<PS>::expand_space_dimension(Variable var,
                                              dimension_type m) {
  Pointset_Powerset& x = *this;
  for (Sequence_iterator si = x.sequence.begin(),
         s_end = x.sequence.end(); si != s_end; ++si)
    si->element().expand_space_dimension(var, m);
  x.space_dim += m;
  assert(x.OK());
}

template <typename PS>
void
Pointset_Powerset<PS>::fold_space_dimensions(const Variables_Set& to_be_folded,
                                             Variable var) {
  Pointset_Powerset& x = *this;
  Variables_Set::size_type num_folded = to_be_folded.size();
  if (num_folded > 0) {
    for (Sequence_iterator si = x.sequence.begin(),
           s_end = x.sequence.end(); si != s_end; ++si)
      si->element().fold_space_dimensions(to_be_folded, var);
  }
  x.space_dim -= num_folded;
  assert(x.OK());
}

template <typename PS>
void
Pointset_Powerset<PS>::affine_image(Variable var,
                                    const Linear_Expression& expr,
                                    Coefficient_traits::const_reference
                                    denominator) {
  Pointset_Powerset& x = *this;
  for (Sequence_iterator si = x.sequence.begin(),
         s_end = x.sequence.end(); si != s_end; ++si) {
    si->element().affine_image(var, expr, denominator);
    // Note that the underlying domain can apply conservative approximation:
    // that is why it would not be correct to make the loss of reduction
    // conditional on `var' and `expr'.
    x.reduced = false;
  }
  assert(x.OK());
}

template <typename PS>
void
Pointset_Powerset<PS>::affine_preimage(Variable var,
                                       const Linear_Expression& expr,
                                       Coefficient_traits::const_reference
                                       denominator) {
  Pointset_Powerset& x = *this;
  for (Sequence_iterator si = x.sequence.begin(),
         s_end = x.sequence.end(); si != s_end; ++si) {
    si->element().affine_preimage(var, expr, denominator);
    // Note that the underlying domain can apply conservative approximation:
    // that is why it would not be correct to make the loss of reduction
    // conditional on `var' and `expr'.
    x.reduced = false;
  }
  assert(x.OK());
}


template <typename PS>
void
Pointset_Powerset<PS>
::generalized_affine_image(const Linear_Expression& lhs,
                           const Relation_Symbol relsym,
                           const Linear_Expression& rhs) {
  Pointset_Powerset& x = *this;
  for (Sequence_iterator si = x.sequence.begin(),
         s_end = x.sequence.end(); si != s_end; ++si) {
    si->element().generalized_affine_image(lhs, relsym, rhs);
    x.reduced = false;
  }
  assert(x.OK());
}

template <typename PS>
void
Pointset_Powerset<PS>
::generalized_affine_preimage(const Linear_Expression& lhs,
                              const Relation_Symbol relsym,
                              const Linear_Expression& rhs) {
  Pointset_Powerset& x = *this;
  for (Sequence_iterator si = x.sequence.begin(),
         s_end = x.sequence.end(); si != s_end; ++si) {
    si->element().generalized_affine_preimage(lhs, relsym, rhs);
    x.reduced = false;
  }
  assert(x.OK());
}

template <typename PS>
void
Pointset_Powerset<PS>
::generalized_affine_image(Variable var,
                           const Relation_Symbol relsym,
                           const Linear_Expression& expr,
                           Coefficient_traits::const_reference denominator) {
  Pointset_Powerset& x = *this;
  for (Sequence_iterator si = x.sequence.begin(),
         s_end = x.sequence.end(); si != s_end; ++si) {
    si->element().generalized_affine_image(var, relsym, expr, denominator);
    x.reduced = false;
  }
  assert(x.OK());
}

template <typename PS>
void
Pointset_Powerset<PS>
::generalized_affine_preimage(Variable var,
                              const Relation_Symbol relsym,
                              const Linear_Expression& expr,
                              Coefficient_traits::const_reference denominator) {  Pointset_Powerset& x = *this;
  for (Sequence_iterator si = x.sequence.begin(),
         s_end = x.sequence.end(); si != s_end; ++si) {
    si->element().generalized_affine_preimage(var, relsym, expr, denominator);
    x.reduced = false;
  }
  assert(x.OK());
}


template <typename PS>
void
Pointset_Powerset<PS>
::bounded_affine_image(Variable var,
                       const Linear_Expression& lb_expr,
                       const Linear_Expression& ub_expr,
                       Coefficient_traits::const_reference denominator) {
  Pointset_Powerset& x = *this;
  for (Sequence_iterator si = x.sequence.begin(),
         s_end = x.sequence.end(); si != s_end; ++si) {
    si->element().bounded_affine_image(var, lb_expr, ub_expr, denominator);
    x.reduced = false;
  }
  assert(x.OK());
}

template <typename PS>
void
Pointset_Powerset<PS>
::bounded_affine_preimage(Variable var,
                          const Linear_Expression& lb_expr,
                          const Linear_Expression& ub_expr,
                          Coefficient_traits::const_reference denominator) {
  Pointset_Powerset& x = *this;
  for (Sequence_iterator si = x.sequence.begin(),
         s_end = x.sequence.end(); si != s_end; ++si) {
    si->element().bounded_affine_preimage(var, lb_expr, ub_expr,
                                          denominator);
    x.reduced = false;
  }
  assert(x.OK());
}

template <typename PS>
dimension_type
Pointset_Powerset<PS>::affine_dimension() const {
  // The affine dimension of the powerset is the affine dimension of
  // the smallest vector space in which it can be embedded.
  const Pointset_Powerset& x = *this;
  C_Polyhedron x_ph(space_dim, EMPTY);

  for (Sequence_const_iterator si = x.sequence.begin(),
         s_end = x.sequence.end(); si != s_end; ++si) {
    PS pi(si->element());
    if (!pi.is_empty()) {
      C_Polyhedron phi(space_dim);
      const Constraint_System& cs = pi.minimized_constraints();
      for (Constraint_System::const_iterator i = cs.begin(),
             cs_end = cs.end(); i != cs_end; ++i) {
        const Constraint& c = *i;
        if (c.is_equality())
          phi.add_constraint(c);
      }
      x_ph.poly_hull_assign(phi);
    }
  }

  return x_ph.affine_dimension();
}

template <typename PS>
bool
Pointset_Powerset<PS>::is_universe() const {
  const Pointset_Powerset& x = *this;
  // Exploit omega-reduction, if already computed.
  if (x.is_omega_reduced())
    return x.size() == 1 && x.begin()->element().is_universe();

  // A powerset is universe iff one of its disjuncts is.
  for (const_iterator x_i = x.begin(), x_end = x.end(); x_i != x_end; ++x_i)
    if (x_i->element().is_universe()) {
      // Speculative omega-reduction, if it is worth.
      if (x.size() > 1) {
        Pointset_Powerset<PS> universe(x.space_dimension(), UNIVERSE);
        Pointset_Powerset& xx = const_cast<Pointset_Powerset&>(x);
        xx.swap(universe);
      }
      return true;
    }
  return false;
}

template <typename PS>
bool
Pointset_Powerset<PS>::is_empty() const {
  const Pointset_Powerset& x = *this;
  for (Sequence_const_iterator si = x.sequence.begin(),
         s_end = x.sequence.end(); si != s_end; ++si)
    if (!si->element().is_empty())
      return false;
  return true;
}

template <typename PS>
bool
Pointset_Powerset<PS>::is_discrete() const {
  const Pointset_Powerset& x = *this;
  for (Sequence_const_iterator si = x.sequence.begin(),
         s_end = x.sequence.end(); si != s_end; ++si)
    if (!si->element().is_discrete())
      return false;
  return true;
}

template <typename PS>
bool
Pointset_Powerset<PS>::is_topologically_closed() const {
  const Pointset_Powerset& x = *this;
  // The powerset must be omega-reduced before checking
  // topological closure.
  x.omega_reduce();
  for (Sequence_const_iterator si = x.sequence.begin(),
         s_end = x.sequence.end(); si != s_end; ++si)
    if (!si->element().is_topologically_closed())
      return false;
  return true;
}

template <typename PS>
bool
Pointset_Powerset<PS>::is_bounded() const {
  const Pointset_Powerset& x = *this;
  for (Sequence_const_iterator si = x.sequence.begin(),
         s_end = x.sequence.end(); si != s_end; ++si)
    if (!si->element().is_bounded())
      return false;
  return true;
}

template <typename PS>
bool
Pointset_Powerset<PS>::constrains(Variable var) const {
  const Pointset_Powerset& x = *this;
  // `var' should be one of the dimensions of the powerset.
  const dimension_type var_space_dim = var.space_dimension();
  if (x.space_dimension() < var_space_dim) {
    std::ostringstream s;
    s << "PPL::Pointset_Powerset<PS>::constrains(v):\n"
      << "this->space_dimension() == " << x.space_dimension() << ", "
      << "v.space_dimension() == " << var_space_dim << ".";
    throw std::invalid_argument(s.str());
  }
  // omega_reduction needed, since a redundant disjunct may constrain var.
  x.omega_reduce();
  // An empty powerset constrains all variables.
  if (x.is_empty())
    return true;
  for (const_iterator x_i = x.begin(), x_end = x.end(); x_i != x_end; ++x_i)
    if (x_i->element().constrains(var))
      return true;
  return false;
}

template <typename PS>
bool
Pointset_Powerset<PS>::is_disjoint_from(const Pointset_Powerset& y) const {
  const Pointset_Powerset& x = *this;
  for (Sequence_const_iterator si = x.sequence.begin(),
         xs_end = x.sequence.end(); si != xs_end; ++si) {
    const PS& pi = si->element();
    for (Sequence_const_iterator sj = y.sequence.begin(),
           ys_end = y.sequence.end(); sj != ys_end; ++sj) {
      const PS& pj = sj->element();
      if (!pi.is_disjoint_from(pj))
        return false;
    }
  }
  return true;
}

template <typename PS>
void
Pointset_Powerset<PS>::topological_closure_assign() {
  Pointset_Powerset& x = *this;
  for (Sequence_iterator si = x.sequence.begin(),
         s_end = x.sequence.end(); si != s_end; ++si)
    si->element().topological_closure_assign();
  assert(x.OK());
}

template <typename PS>
bool
Pointset_Powerset<PS>
::intersection_preserving_enlarge_element(PS& to_be_enlarged) const {
  // FIXME: this is just an executable specification.
  const Pointset_Powerset& context = *this;
  assert(context.space_dimension() == to_be_enlarged.space_dimension());
  bool nonempty_intersection = false;
  // TODO: maybe use a *sorted* constraint system?
  PS enlarged(context.space_dimension(), UNIVERSE);
  for (Sequence_const_iterator si = context.sequence.begin(),
         s_end = context.sequence.end(); si != s_end; ++si) {
    PS context_i(si->element());
    context_i.intersection_assign(enlarged);
    PS enlarged_i(to_be_enlarged);
    nonempty_intersection
      |= enlarged_i.simplify_using_context_assign(context_i);
    // TODO: merge the sorted constraints of `enlarged' and `enlarged_i'?
    enlarged.intersection_assign(enlarged_i);
  }
  to_be_enlarged.swap(enlarged);
  return nonempty_intersection;
}

template <typename PS>
bool
Pointset_Powerset<PS>
::simplify_using_context_assign(const Pointset_Powerset& y) {
  Pointset_Powerset& x = *this;

  // Omega reduction is required.
  // TODO: check whether it would be more efficient to Omega-reduce x
  // during the simplification process: when examining *si, we check
  // if it has been made redundant by any of the elements preceding it
  // (which have been already simplified).
  x.omega_reduce();
  if (x.is_empty())
    return false;
  y.omega_reduce();
  if (y.is_empty()) {
    x = y;
    return false;
  }

  if (y.size() == 1) {
    // More efficient, special handling of the singleton context case.
    const PS& y_i = y.sequence.begin()->element();
    for (Sequence_iterator si = x.sequence.begin(),
           s_end = x.sequence.end(); si != s_end; ) {
      PS& x_i = si->element();
      if (x_i.simplify_using_context_assign(y_i))
        ++si;
      else
        // Intersection is empty: drop the disjunct.
        si = x.sequence.erase(si);
    }
  }
  else {
    // The context is not a singleton.
    for (Sequence_iterator si = x.sequence.begin(),
           s_end = x.sequence.end(); si != s_end; ) {
      if (y.intersection_preserving_enlarge_element(si->element()))
        ++si;
      else
        // Intersection with `*si' is empty: drop the disjunct.
        si = x.sequence.erase(si);
    }
  }
  x.reduced = false;
  assert(x.OK());
  return !x.sequence.empty();
}

template <typename PS>
bool
Pointset_Powerset<PS>::contains(const Pointset_Powerset& y) const {
  const Pointset_Powerset& x = *this;
  for (Sequence_const_iterator si = y.sequence.begin(),
         ys_end = y.sequence.end(); si != ys_end; ++si) {
    const PS& pi = si->element();
    bool pi_is_contained = false;
    for (Sequence_const_iterator sj = x.sequence.begin(),
           xs_end = x.sequence.end();
         (sj != xs_end && !pi_is_contained); ++sj) {
      const PS& pj = sj->element();
      if (pj.contains(pi))
        pi_is_contained = true;
    }
    if (!pi_is_contained)
      return false;
  }
  return true;
}

template <typename PS>
bool
Pointset_Powerset<PS>::strictly_contains(const Pointset_Powerset& y) const {
  /* omega reduction ensures that a disjunct of y cannot be strictly
     contained in one disjunct and also contained but not strictly
     contained in another disjunct of *this */
  const Pointset_Powerset& x = *this;
  x.omega_reduce();
  for (Sequence_const_iterator si = y.sequence.begin(),
         ys_end = y.sequence.end(); si != ys_end; ++si) {
    const PS& pi = si->element();
    bool pi_is_strictly_contained = false;
    for (Sequence_const_iterator sj = x.sequence.begin(),
           xs_end = x.sequence.end();
         (sj != xs_end && !pi_is_strictly_contained); ++sj) {
      const PS& pj = sj->element();
      if (pj.strictly_contains(pi))
        pi_is_strictly_contained = true;
    }
    if (!pi_is_strictly_contained)
      return false;
  }
  return true;
}

template <typename PS>
Poly_Con_Relation
Pointset_Powerset<PS>::relation_with(const Congruence& cg) const {
  const Pointset_Powerset& x = *this;

  /* *this is included in cg if every disjunct is included in cg */
  bool is_included = true;
  /* *this is disjoint with cg if every disjunct is disjoint with cg */
  bool is_disjoint = true;
  /* *this strictly_intersects with cg if some disjunct strictly
     intersects with cg */
  bool is_strictly_intersecting = false;
  /* *this saturates cg if some disjunct saturates cg and
     every disjunct is either disjoint from cg or saturates cg */
  bool saturates_once = false;
  bool may_saturate = true;
  for (Sequence_const_iterator si = x.sequence.begin(),
         s_end = x.sequence.end(); si != s_end; ++si) {
    Poly_Con_Relation relation_i = si->element().relation_with(cg);
    if (!relation_i.implies(Poly_Con_Relation::is_included()))
      is_included = false;
    if (!relation_i.implies(Poly_Con_Relation::is_disjoint()))
      is_disjoint = false;
    if (relation_i.implies(Poly_Con_Relation::strictly_intersects()))
      is_strictly_intersecting = true;
    if (relation_i.implies(Poly_Con_Relation::saturates()))
      saturates_once = true;
    else if (!relation_i.implies(Poly_Con_Relation::is_disjoint()))
      may_saturate = false;
  }

  Poly_Con_Relation result = Poly_Con_Relation::nothing();
  if (is_included)
    result = result && Poly_Con_Relation::is_included();
  if (is_disjoint)
    result = result && Poly_Con_Relation::is_disjoint();
  if (is_strictly_intersecting)
    result = result && Poly_Con_Relation::strictly_intersects();
  if (saturates_once && may_saturate)
    result = result && Poly_Con_Relation::saturates();

  return result;
}

template <typename PS>
Poly_Con_Relation
Pointset_Powerset<PS>::relation_with(const Constraint& c) const {
  const Pointset_Powerset& x = *this;

  /* *this is included in c if every disjunct is included in c */
  bool is_included = true;
  /* *this is disjoint with c if every disjunct is disjoint with c */
  bool is_disjoint = true;
  /* *this strictly_intersects with c if some disjunct strictly
     intersects with c */
  bool is_strictly_intersecting = false;
  /* *this saturates c if some disjunct saturates c and
     every disjunct is either disjoint from c or saturates c */
  bool saturates_once = false;
  bool may_saturate = true;
  for (Sequence_const_iterator si = x.sequence.begin(),
         s_end = x.sequence.end(); si != s_end; ++si) {
    Poly_Con_Relation relation_i = si->element().relation_with(c);
    if (!relation_i.implies(Poly_Con_Relation::is_included()))
      is_included = false;
    if (!relation_i.implies(Poly_Con_Relation::is_disjoint()))
      is_disjoint = false;
    if (relation_i.implies(Poly_Con_Relation::strictly_intersects()))
      is_strictly_intersecting = true;
    if (relation_i.implies(Poly_Con_Relation::saturates()))
      saturates_once = true;
    else if (!relation_i.implies(Poly_Con_Relation::is_disjoint()))
      may_saturate = false;
  }

  Poly_Con_Relation result = Poly_Con_Relation::nothing();
  if (is_included)
    result = result && Poly_Con_Relation::is_included();
  if (is_disjoint)
    result = result && Poly_Con_Relation::is_disjoint();
  if (is_strictly_intersecting)
    result = result && Poly_Con_Relation::strictly_intersects();
  if (saturates_once && may_saturate)
    result = result && Poly_Con_Relation::saturates();

  return result;
}

template <typename PS>
Poly_Gen_Relation
Pointset_Powerset<PS>::relation_with(const Generator& g) const {
  const Pointset_Powerset& x = *this;

  for (Sequence_const_iterator si = x.sequence.begin(),
         s_end = x.sequence.end(); si != s_end; ++si) {
    Poly_Gen_Relation relation_i = si->element().relation_with(g);
    if (relation_i.implies(Poly_Gen_Relation::subsumes()))
      return Poly_Gen_Relation::subsumes();
  }

  return Poly_Gen_Relation::nothing();
}

template <typename PS>
bool
Pointset_Powerset<PS>
::bounds_from_above(const Linear_Expression& expr) const {
  const Pointset_Powerset& x = *this;
  x.omega_reduce();
  for (Sequence_const_iterator si = x.sequence.begin(),
         s_end = x.sequence.end(); si != s_end; ++si)
    if (!si->element().bounds_from_above(expr))
      return false;
  return true;
}

template <typename PS>
bool
Pointset_Powerset<PS>
::bounds_from_below(const Linear_Expression& expr) const {
  const Pointset_Powerset& x = *this;
  x.omega_reduce();
  for (Sequence_const_iterator si = x.sequence.begin(),
         s_end = x.sequence.end(); si != s_end; ++si)
    if (!si->element().bounds_from_below(expr))
      return false;
  return true;
}

template <typename PS>
bool
Pointset_Powerset<PS>::maximize(const Linear_Expression& expr,
                                Coefficient& sup_n,
                                Coefficient& sup_d,
                                bool& maximum) const {
  const Pointset_Powerset& x = *this;
  x.omega_reduce();
  bool first = true;

  PPL_DIRTY_TEMP_COEFFICIENT(supt_n);
  PPL_DIRTY_TEMP_COEFFICIENT(supt_d);
  supt_n = 0;
  supt_d = 1;
  bool maxt = 0;

  PPL_DIRTY_TEMP_COEFFICIENT(supi_n);
  PPL_DIRTY_TEMP_COEFFICIENT(supi_d);
  supi_n = 0;
  supi_d = 1;
  bool maxi = 0;

  PPL_DIRTY_TEMP_COEFFICIENT(tmp);

  for (Sequence_const_iterator si = x.sequence.begin(),
         s_end = x.sequence.end(); si != s_end; ++si) {
    if (!si->element().maximize(expr, supi_n, supi_d, maxi))
      return false;
    else
      if (first) {
        first = false;
        supt_n = supi_n;
        supt_d = supi_d;
        maxt = maxi;
      }
      else {
        tmp = (supt_n * supi_d) - (supi_n * supt_d);
        if (tmp < 0) {
          supt_n = supi_n;
          supt_d = supi_d;
          maxt = maxi;
        }
        else if (tmp == 0)
          maxt = maxt || maxi;
      }
  }
  sup_n = supt_n;
  sup_d = supt_d;
  maximum = maxt;
  return true;
}

template <typename PS>
bool
Pointset_Powerset<PS>::maximize(const Linear_Expression& expr,
                                Coefficient& sup_n,
                                Coefficient& sup_d,
                                bool& maximum,
                                Generator& g) const {
  const Pointset_Powerset& x = *this;
  x.omega_reduce();
  bool first = true;

  PPL_DIRTY_TEMP_COEFFICIENT(supt_n);
  PPL_DIRTY_TEMP_COEFFICIENT(supt_d);
  supt_n = 0;
  supt_d = 1;
  bool maxt = 0;
  Generator gt = point();

  PPL_DIRTY_TEMP_COEFFICIENT(supi_n);
  PPL_DIRTY_TEMP_COEFFICIENT(supi_d);
  supi_n = 0;
  supi_d = 1;
  bool maxi = 0;
  Generator gi = point();

  PPL_DIRTY_TEMP_COEFFICIENT(tmp);

  for (Sequence_const_iterator si = x.sequence.begin(),
         s_end = x.sequence.end(); si != s_end; ++si) {
    if (!si->element().maximize(expr, supi_n, supi_d, maxi, gi))
      return false;
    else
      if (first) {
        first = false;
        supt_n = supi_n;
        supt_d = supi_d;
        maxt = maxi;
        gt = gi;
      }
      else {
        tmp = (supt_n * supi_d) - (supi_n * supt_d);
        if (tmp < 0) {
          supt_n = supi_n;
          supt_d = supi_d;
          maxt = maxi;
          gt = gi;
        }
        else if (tmp == 0) {
          maxt = maxt || maxi;
          gt = gi;
        }
      }
  }
  sup_n = supt_n;
  sup_d = supt_d;
  maximum = maxt;
  g = gt;
  return true;
}

template <typename PS>
bool
Pointset_Powerset<PS>::minimize(const Linear_Expression& expr,
                                Coefficient& inf_n,
                                Coefficient& inf_d,
                                bool& minimum) const {
  const Pointset_Powerset& x = *this;
  x.omega_reduce();
  bool first = true;

  PPL_DIRTY_TEMP_COEFFICIENT(inft_n);
  PPL_DIRTY_TEMP_COEFFICIENT(inft_d);
  inft_n = 0;
  inft_d = 1;
  bool mint = 0;

  PPL_DIRTY_TEMP_COEFFICIENT(infi_n);
  PPL_DIRTY_TEMP_COEFFICIENT(infi_d);
  infi_n = 0;
  infi_d = 1;
  bool mini = 0;

  PPL_DIRTY_TEMP_COEFFICIENT(tmp);

  for (Sequence_const_iterator si = x.sequence.begin(),
         s_end = x.sequence.end(); si != s_end; ++si) {
    if (!si->element().minimize(expr, infi_n, infi_d, mini))
      return false;
    else
      if (first) {
        first = false;
        inft_n = infi_n;
        inft_d = infi_d;
        mint = mini;
      }
      else {
        tmp = (inft_n * infi_d) - (infi_n * inft_d);
        if (tmp > 0) {
          inft_n = infi_n;
          inft_d = infi_d;
          mint = mini;
        }
        else if (tmp == 0)
          mint = mint || mini;
      }
  }
  inf_n = inft_n;
  inf_d = inft_d;
  minimum = mint;
  return true;
}

template <typename PS>
bool
Pointset_Powerset<PS>::minimize(const Linear_Expression& expr,
                                Coefficient& inf_n,
                                Coefficient& inf_d,
                                bool& minimum,
                                Generator& g) const {
  const Pointset_Powerset& x = *this;
  x.omega_reduce();
  bool first = true;

  PPL_DIRTY_TEMP_COEFFICIENT(inft_n);
  PPL_DIRTY_TEMP_COEFFICIENT(inft_d);
  inft_n = 0;
  inft_d = 1;
  bool mint = 0;
  Generator gt = point();

  PPL_DIRTY_TEMP_COEFFICIENT(infi_n);
  PPL_DIRTY_TEMP_COEFFICIENT(infi_d);
  infi_n = 0;
  infi_d = 1;
  bool mini = 0;
  Generator gi = point();

  PPL_DIRTY_TEMP_COEFFICIENT(tmp);

  for (Sequence_const_iterator si = x.sequence.begin(),
         s_end = x.sequence.end(); si != s_end; ++si) {
    if (!si->element().minimize(expr, infi_n, infi_d, mini, gi))
      return false;
    else
      if (first) {
        first = false;
        inft_n = infi_n;
        inft_d = infi_d;
        mint = mini;
        gt = gi;
      }
      else {
        tmp = (inft_n * infi_d) - (infi_n * inft_d);
        if (tmp > 0) {
          inft_n = infi_n;
          inft_d = infi_d;
          mint = mini;
          gt = gi;
        }
        else if (tmp == 0) {
          mint = mint || mini;
          gt = gi;
        }
      }
  }
  inf_n = inft_n;
  inf_d = inft_d;
  minimum = mint;
  g = gt;
  return true;
}

template <typename PS>
bool
Pointset_Powerset<PS>::contains_integer_point() const {
  const Pointset_Powerset& x = *this;
  for (Sequence_const_iterator si = x.sequence.begin(),
         s_end = x.sequence.end(); si != s_end; ++si)
    if (si->element().contains_integer_point())
      return true;
  return false;
}

template <typename PS>
void
Pointset_Powerset<PS>::pairwise_reduce() {
  Pointset_Powerset& x = *this;
  // It is wise to omega-reduce before pairwise-reducing.
  x.omega_reduce();

  size_type n = x.size();
  size_type deleted;
  do {
    Pointset_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;
      PS& 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 PS& pj = sj->element();
	if (pi.upper_bound_assign_if_exact(pj)) {
	  marked[si_index] = marked[sj_index] = true;
	  new_x.add_non_bottom_disjunct_preserve_reduction(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_preserve_reduction(*xi,
								    nx_begin,
								    nx_end);
    std::swap(x.sequence, new_x.sequence);
    n -= deleted;
  } while (deleted > 0);
  assert(x.OK());
}

template <typename PS>
template <typename Widening>
void
Pointset_Powerset<PS>::
BGP99_heuristics_assign(const Pointset_Powerset& y, Widening wf) {
  // `x' is the current iteration value.
  Pointset_Powerset& x = *this;

#ifndef NDEBUG
  {
    // We assume that `y' entails `x'.
    const Pointset_Powerset<PS> x_copy = x;
    const Pointset_Powerset<PS> y_copy = y;
    assert(y_copy.definitely_entails(x_copy));
  }
#endif

  size_type n = x.size();
  Pointset_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 PS& pi = i->element();
      const PS& pj = j->element();
      if (pi.contains(pj)) {
	PS pi_copy = pi;
	wf(pi_copy, pj);
	new_x.add_non_bottom_disjunct_preserve_reduction(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_preserve_reduction(*i,
								  nx_begin,
								  nx_end);
  std::swap(x.sequence, new_x.sequence);
  assert(x.OK());
  assert(x.is_omega_reduced());
}

template <typename PS>
template <typename Widening>
void
Pointset_Powerset<PS>::
BGP99_extrapolation_assign(const Pointset_Powerset& y,
			   Widening wf,
			   unsigned max_disjuncts) {
  // `x' is the current iteration value.
  Pointset_Powerset& x = *this;

#ifndef NDEBUG
  {
    // We assume that `y' entails `x'.
    const Pointset_Powerset<PS> x_copy = x;
    const Pointset_Powerset<PS> 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 PS>
template <typename Cert>
void
Pointset_Powerset<PS>::
collect_certificates(std::map<Cert, size_type,
                     typename Cert::Compare>& cert_ms) const {
  const Pointset_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 PS>
template <typename Cert>
bool
Pointset_Powerset<PS>::
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(),
    x_cert_ms_end = x_cert_ms.end(),
    yi = y_cert_ms.begin(),
    y_cert_ms_end = y_cert_ms.end();
  while (xi != x_cert_ms_end && yi != y_cert_ms_end) {
    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 == x_cert_ms_end or yi == y_cert_ms_end.
  // Stabilization is achieved if `y_cert_ms' still has other elements.
  return yi != y_cert_ms_end;
}

template <typename PS>
template <typename Cert, typename Widening>
void
Pointset_Powerset<PS>::BHZ03_widening_assign(const Pointset_Powerset& y,
                                             Widening wf) {
  // `x' is the current iteration value.
  Pointset_Powerset& x = *this;

#ifndef NDEBUG
  {
    // We assume that `y' entails `x'.
    const Pointset_Powerset<PS> x_copy = x;
    const Pointset_Powerset<PS> 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'.
  PS 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'.
  PS 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.
  Pointset_Powerset<PS> bgp99_heuristics = x;
  bgp99_heuristics.BGP99_heuristics_assign(y, wf);

  // Compute the poly-hull of `bgp99_heuristics'.
  PS 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.
    Pointset_Powerset<PS> 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).
    PS 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.
  Pointset_Powerset<PS> x_hull_singleton(x.space_dim, EMPTY);
  x_hull_singleton.add_disjunct(x_hull);
  std::swap(x, x_hull_singleton);
}

template <typename PS>
void
Pointset_Powerset<PS>::ascii_dump(std::ostream& s) const {
  const Pointset_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(PS, Pointset_Powerset<PS>)

  template <typename PS>
bool
Pointset_Powerset<PS>::ascii_load(std::istream& s) {
  Pointset_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;

  Pointset_Powerset new_x(x.space_dim, EMPTY);
  while (sz-- > 0) {
    PS ph;
    if (!ph.ascii_load(s))
      return false;
    new_x.add_disjunct(ph);
  }
  x.swap(new_x);

  // Check invariants.
  assert(x.OK());
  return true;
}

template <typename PS>
bool
Pointset_Powerset<PS>::OK() const {
  const Pointset_Powerset& x = *this;
  for (const_iterator xi = x.begin(), x_end = x.end(); xi != x_end; ++xi) {
    const PS& 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 Pointset_Powersets {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Partitions polyhedron \p qq according to constraint \p c.
/*! \relates Parma_Polyhedra_Library::Pointset_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 // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
template <typename PS>
void
linear_partition_aux(const Constraint& c,
		     PS& qq,
		     Pointset_Powerset<NNC_Polyhedron>& r) {
  Linear_Expression le(c);
  const Constraint& neg_c = c.is_strict_inequality() ? (le <= 0) : (le < 0);
  NNC_Polyhedron qqq(qq);
  qqq.add_constraint(neg_c);
  if (!qqq.is_empty())
    r.add_disjunct(qqq);
  qq.add_constraint(c);
}

} // namespace Pointset_Powersets

} // namespace Implementation


/*! \relates Pointset_Powerset */
template <typename PS>
std::pair<PS, Pointset_Powerset<NNC_Polyhedron> >
linear_partition(const PS& p, const PS& q) {
  using Implementation::Pointset_Powersets::linear_partition_aux;

  Pointset_Powerset<NNC_Polyhedron> r(p.space_dimension(), EMPTY);
  PS 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::make_pair(qq, r);
}

} // namespace Parma_Polyhedra_Library

/* Automatically generated from PPL source file ../src/Pointset_Powerset.defs.hh line 1448. */

/* 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 // defined(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 // defined(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, Pointset_Powerset<NNC_Polyhedron> >
    partition = linear_partition(q, phull);
  const Pointset_Powerset<NNC_Polyhedron>& s = partition.second;
  typedef Pointset_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

/* Automatically generated from PPL source file ../src/wrap.hh line 1. */
/* Declaration of string wrapping function.
*/


/* Automatically generated from PPL source file ../src/wrap.hh line 27. */

namespace Parma_Polyhedra_Library {

namespace IO_Operators {

//! Utility function for the wrapping of lines of text.
/*!
  \param src_string
  The source string holding the lines to wrap.

  \param indent_depth
  The indentation depth.

  \param preferred_first_line_length
  The preferred length for the first line of text.

  \param preferred_line_length
  The preferred length for all the lines but the first one.

  \return
  The wrapped string.
*/
std::string
wrap_string(const std::string& src_string,
	    unsigned indent_depth,
	    unsigned preferred_first_line_length,
	    unsigned preferred_line_length);

} // namespace IO_Operators

} // namespace Parma_Polyhedra_Library


#undef PPL_SPECIALIZE_ABS
#undef PPL_SPECIALIZE_ADD
#undef PPL_SPECIALIZE_ADD_MUL
#undef PPL_SPECIALIZE_ASSIGN
#undef PPL_SPECIALIZE_ASSIGN_SPECIAL
#undef PPL_SPECIALIZE_CEIL
#undef PPL_SPECIALIZE_CLASSIFY
#undef PPL_SPECIALIZE_CMP
#undef PPL_SPECIALIZE_CONSTRUCT
#undef PPL_SPECIALIZE_CONSTRUCT_SPECIAL
#undef PPL_SPECIALIZE_COPY
#undef PPL_SPECIALIZE_DIV
#undef PPL_SPECIALIZE_DIV2EXP
#undef PPL_SPECIALIZE_FLOOR
#undef PPL_SPECIALIZE_FUN1_0_0
#undef PPL_SPECIALIZE_FUN1_0_1
#undef PPL_SPECIALIZE_FUN1_0_2
#undef PPL_SPECIALIZE_FUN1_0_3
#undef PPL_SPECIALIZE_FUN1_1_1
#undef PPL_SPECIALIZE_FUN1_1_2
#undef PPL_SPECIALIZE_FUN1_2_2
#undef PPL_SPECIALIZE_FUN2_0_0
#undef PPL_SPECIALIZE_FUN2_0_1
#undef PPL_SPECIALIZE_FUN2_0_2
#undef PPL_SPECIALIZE_FUN3_0_1
#undef PPL_SPECIALIZE_FUN5_0_1
#undef PPL_SPECIALIZE_GCD
#undef PPL_SPECIALIZE_GCDEXT
#undef PPL_SPECIALIZE_IDIV
#undef PPL_SPECIALIZE_INPUT
#undef PPL_SPECIALIZE_IS_INT
#undef PPL_SPECIALIZE_IS_MINF
#undef PPL_SPECIALIZE_IS_NAN
#undef PPL_SPECIALIZE_IS_PINF
#undef PPL_SPECIALIZE_LCM
#undef PPL_SPECIALIZE_MUL
#undef PPL_SPECIALIZE_MUL2EXP
#undef PPL_SPECIALIZE_NEG
#undef PPL_SPECIALIZE_OUTPUT
#undef PPL_SPECIALIZE_REM
#undef PPL_SPECIALIZE_SGN
#undef PPL_SPECIALIZE_SQRT
#undef PPL_SPECIALIZE_SUB
#undef PPL_SPECIALIZE_SUB_MUL
#undef PPL_SPECIALIZE_TRUNC

#undef PPL_COMPILE_TIME_CHECK
#undef PPL_COMPILE_TIME_CHECK_AUX
#undef PPL_COMPILE_TIME_CHECK_NAME

#ifdef __STDC_LIMIT_MACROS
# undef __STDC_LIMIT_MACROS
#endif
#ifdef PPL_SAVE_STDC_LIMIT_MACROS
# define __STDC_LIMIT_MACROS PPL_SAVE_STDC_LIMIT_MACROS
# undef PPL_SAVE_STDC_LIMIT_MACROS
#endif

#ifdef PPL_SAVE_NDEBUG
# ifndef NDEBUG
#  define NDEBUG PPL_SAVE_NDEBUG
# endif
# undef PPL_SAVE_NDEBUG
#else
# ifdef NDEBUG
#  undef NDEBUG
# endif
#endif
#include <cassert>

#ifdef PPL_NO_AUTOMATIC_INITIALIZATION
 #undef PPL_NO_AUTOMATIC_INITIALIZATION
#endif

#endif
