/* Header file for the C interface.  -*- C -*-
   Copyright (C) 2001-2006 Roberto Bagnara <bagnara@cs.unipr.it>

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

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

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

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

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

#ifndef PPL_ppl_c_h
#define PPL_ppl_c_h 1

/*! \defgroup PPL_C_interface C Language Interface

\brief
\ref CInterfaceDetails "Some details about the C Interface".

\anchor CInterfaceDetails
All the declarations needed for using the PPL's C interface
(preprocessor symbols, data types, variables and
functions) are collected in the header file <CODE>ppl_c.h</CODE>.
This file, which is designed to work with pre-ANSI and ANSI C compilers
as well as C99 and C++ compilers, should be included, either directly
or via some other header file, with the directive
\code
#include <ppl_c.h>
\endcode
If this directive does not work, then your compiler is unable to find
the file <CODE>ppl_c.h</CODE>. So check that the library is installed
(if it is not installed, you may want to <CODE>make install</CODE>,
perhaps with root privileges) in the right place
(if not you may want to reconfigure the library using the appropriate
pathname for the <CODE>--prefix</CODE> option); and that your compiler
knows where it is installed (if not you should add the path to the
directory where <CODE>ppl_c.h</CODE> is located to the compiler's
include file search path; this is usually done with the
<CODE>-I</CODE> option).

The name space of the PPL's C interface is <CODE>PPL_*</CODE> for
preprocessor symbols, enumeration values and variables; and
<CODE>ppl_*</CODE> for data types and function names. The interface
systematically uses <EM>opaque data types</EM> (generic pointers that
completely hide the internal representations from the client code) and
provides all required access functions. By using just the interface,
the client code can exploit all the functionalities of the library yet
avoid directly manipulating the library's data structures.  The advantages
are that (1) applications do not depend on the internals of the library
(these may change from release to release), and (2) the interface
invariants can be thoroughly checked (by the access functions).

The PPL's C interface is initialized by means of the
<CODE>ppl_initialize</CODE> function.  This function must
be called <EM>before using any other interface of the library</EM>.
The application can release the resources allocated by the library by
calling the <CODE>ppl_finalize</CODE> function. After this function
is called <EM>no other interface of the library may be used</EM>
until the interface is re-initialized using <CODE>ppl_initialize</CODE>.

Any application using the PPL should make sure that only the
intended version(s) of the library are ever used.  The version used can be
checked at compile-time thanks to the macros PPL_VERSION_MAJOR,
PPL_VERSION_MINOR, PPL_VERSION_REVISION and PPL_VERSION_BETA, which
give, respectively major, minor, revision and beta numbers of the PPL
version.  This is an example of their use:
\code
#if PPL_VERSION_MAJOR == 0 && PPL_VERSION_MINOR < 6
# error "PPL version 0.6 or following is required"
#endif
\endcode
Compile-time checking, however, is not normally enough, particularly in
an environment where there is dynamic linking.  Run-time checking can
be performed by means of the functions <CODE>ppl_version_major</CODE>,
<CODE>ppl_version_minor</CODE>, <CODE>ppl_version_revision</CODE>, and
<CODE>ppl_version_beta</CODE>. The PPL's C interface also provides
functions <CODE>ppl_version</CODE>, returning character string
containing the full version number, and <CODE>ppl_banner</CODE>,
returning a string that, in addition, provides (pointers to) other
useful information for the library user.

All programs using the PPL's C interface must link with the
following libraries: <CODE>libppl_c</CODE> (PPL's C interface),
<CODE>libppl</CODE> (PPL's core), <CODE>libgmpxx</CODE> (GMP's C++
interface), and <CODE>libgmp</CODE> (GMP's library core).  On most
Unix-like systems, this is done by adding <CODE>-lppl_c</CODE>,
<CODE>-lppl</CODE>, <CODE>-lgmpxx</CODE>, and <CODE>-lgmp</CODE> to
the compiler's or linker's command line.  For example:
\verbatim
gcc myprogram.o -lppl_c -lppl -lgmpxx -lgmp
\endverbatim
If this does not work, it means that your compiler/linker is not
finding the libraries where it expects.  Again, this could be because you
forgot to install the library or you installed it in a non-standard
location.  In the latter case you will need to use the appropriate
options (usually <CODE>-L</CODE>) and, if you use shared libraries,
some sort of run-time path selection mechanisms.  Consult your
compiler's documentation for details.  Notice that the PPL is built
using <A HREF="http://www.gnu.org/software/libtool/">Libtool</A> and
an application can exploit this fact to significantly simplify the
linking phase.  See Libtool's documentation for details.  Those
working under Linux can find a lot of useful information on how to use
program libraries (including static, shared, and dynamically loaded
libraries) in the
<A HREF="http://www.dwheeler.com/program-library/">Program Library
HOWTO</A>.

For examples on how to use the functions provided by the C interface,
you are referred to the directory <CODE>demos/ppl_lpsol/</CODE> in
the source distribution.  It contains a <EM>Linear Programming</EM>
solver written in C.  In order to use this solver you will need to install
<A HREF="http://www.gnu.org/software/glpk/">GLPK</A> (the GNU Linear
Programming Kit): this is used to read linear programs in MPS format.
*/

/*
  For some reason, GMP up to and including version 4.1.3 requires
  <stdio.h> to be included before <gmp.h>.
*/
/*@{*/ /* \defgroup PPL_C_interface */

#include <stdio.h>
#include <gmp.h>
#include <stddef.h>

/*
  PPL_PROTO is a macro used to wrap function prototypes, so that
  compilers that don't understand ANSI C prototypes still work, and
  ANSI C compilers can issue warnings about type mismatches.
*/
#if defined(__STDC__)                              \
  || defined(__cplusplus)                          \
  || defined (_AIX)                                \
  || (defined (__mips) && defined (_SYSTYPE_SVR4)) \
  || defined(_WIN32)
# define PPL_PROTO(protos) protos
#else
# define PPL_PROTO(protos) ()
#endif

#ifdef __cplusplus
extern "C" {
#endif

/*! \brief
  Defines the error codes that any function may return.
*/
enum ppl_enum_error_code {
  /*! \hideinitializer
    The virtual memory available to the process has been exhausted. */
  PPL_ERROR_OUT_OF_MEMORY = -2,
  /*! \hideinitializer
    A function has been invoked with an invalid argument. */
  PPL_ERROR_INVALID_ARGUMENT = -3,
  /*! \hideinitializer
    A function has been invoked outside its domain of definition. */
  PPL_ERROR_DOMAIN_ERROR = -4,
  /*! \hideinitializer
    The construction of an object that would exceed its maximum
    permitted size was attempted. */
  PPL_ERROR_LENGTH_ERROR = -5,
  /*! \hideinitializer
    An arithmetic overflow occurred and the computation was consequently
    interrupted.  This can <EM>only</EM> happen in library's incarnations
    using bounded integers as coefficients. */
  PPL_ARITHMETIC_OVERFLOW = -6,
  /*! \hideinitializer
    An error occurred during a C input/output operation.  A more
    precise indication of what went wrong is available via
    <CODE>errno</CODE>. */
  PPL_STDIO_ERROR = -7,
  /*! \hideinitializer
    An internal error that was diagnosed by the PPL itself.
    This indicates a bug in the PPL. */
  PPL_ERROR_INTERNAL_ERROR = -8,
  /*! \hideinitializer
    A standard exception has been raised by the C++ run-time environment.
    This indicates a bug in the PPL. */
  PPL_ERROR_UNKNOWN_STANDARD_EXCEPTION = -9,
  /*! \hideinitializer
    A totally unknown, totally unexpected error happened.
    This indicates a bug in the PPL. */
  PPL_ERROR_UNEXPECTED_ERROR = -10
};

/*! \name Version Checking */
/*@{*/

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

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

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

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

/*! \brief
  A string containing the PPL version.

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

/*! \brief
  Returns the major number of the PPL version.
*/
int
ppl_version_major PPL_PROTO((void));

/*! \brief
  Returns the minor number of the PPL version.
*/
int
ppl_version_minor PPL_PROTO((void));

/*! \brief
  Returns the revision number of the PPL version.
*/
int
ppl_version_revision PPL_PROTO((void));

/*! \brief
  Returns the beta number of the PPL version.
*/
int
ppl_version_beta PPL_PROTO((void));

/*! \brief
  Writes to \c *p a pointer to a character string containing the
  PPL version.
*/
int
ppl_version PPL_PROTO((const char** p));

/*! \brief
  Writes to \c *p a pointer to 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.
*/
int
ppl_banner PPL_PROTO((const char** p));

/*@}*/ /* Version Checking */

/*! \brief
  An unsigned integral type for representing space dimensions.
*/
typedef size_t ppl_dimension_type;

/*! \name Initialization, Error Handling and Auxiliary Functions */
/*@{*/

/*! \brief
  Writes to \p m the maximum space dimension this library can handle.
*/
int
ppl_max_space_dimension PPL_PROTO((ppl_dimension_type* m));

/*! \brief
  Writes to \p m a value that does not designate a valid dimension.
*/
int
ppl_not_a_dimension PPL_PROTO((ppl_dimension_type* m));

/*! \brief
  Initializes the Parma Polyhedra Library.
  This function must be called before any other function.

  \return
  <CODE>PPL_ERROR_INVALID_ARGUMENT</CODE> if the library
  was already initialized.
*/
int
ppl_initialize PPL_PROTO((void));

/*! \brief
  Finalizes the Parma Polyhedra Library.
  This function must be called after any other function.

  \return
  <CODE>PPL_ERROR_INVALID_ARGUMENT</CODE> if the library
  was already finalized.
*/
int
ppl_finalize PPL_PROTO((void));

/*! \brief
  Installs the user-defined error handler pointed at by \p h.

  The error handler takes an error code and a textual description that
  gives further information about the actual error.  The C string
  containing the textual description is read-only and its existence is
  not guaranteed after the handler has returned.
*/
int
ppl_set_error_handler PPL_PROTO((void (*h)(enum ppl_enum_error_code code,
					   const char* description)));

/*@}*/ /* Initialization, Error Handling and Auxiliary Functions */

#undef PPL_TYPE_DECLARATION

#define PPL_TYPE_DECLARATION(Type) /*! \brief Opaque pointer. */ typedef struct ppl_ ## Type ## _tag* ppl_ ## Type ## _t; /*! \brief Opaque pointer to const object. */ typedef struct ppl_ ## Type ## _tag const* ppl_const_ ## Type ## _t

PPL_TYPE_DECLARATION(Coefficient);

PPL_TYPE_DECLARATION(Linear_Expression);

PPL_TYPE_DECLARATION(Constraint);

PPL_TYPE_DECLARATION(Constraint_System);

PPL_TYPE_DECLARATION(Constraint_System_const_iterator);

PPL_TYPE_DECLARATION(Generator);

PPL_TYPE_DECLARATION(Generator_System);

PPL_TYPE_DECLARATION(Generator_System_const_iterator);

PPL_TYPE_DECLARATION(Polyhedron);

PPL_TYPE_DECLARATION(LP_Problem);

#undef PPL_TYPE_DECLARATION

/*! \name Functions Related to Coefficients */
/*@{*/

/*! \brief
  Creates a new coefficient with value 0 and writes a handle for the
  newly created coefficient at address \p pc.
*/
int
ppl_new_Coefficient PPL_PROTO((ppl_Coefficient_t* pc));

/*! \brief
  Creates a new coefficient with the value given by the GMP integer
  \p z and writes a handle for the newly created coefficient
  at address \p pc.
*/
int
ppl_new_Coefficient_from_mpz_t PPL_PROTO((ppl_Coefficient_t* pc, mpz_t z));

/*! \brief
  Builds a coefficient that is a copy of \p c; writes a handle
  for the newly created coefficient at address \p pc.
*/
int
ppl_new_Coefficient_from_Coefficient PPL_PROTO((ppl_Coefficient_t* pc,
						ppl_const_Coefficient_t c));

/*! \brief
  Assign to \p dst the value given by the GMP integer \p z.
*/
int
ppl_assign_Coefficient_from_mpz_t PPL_PROTO((ppl_Coefficient_t dst, mpz_t z));

/*! \brief
  Assigns a copy of the coefficient \p src to \p dst.
*/
int
ppl_assign_Coefficient_from_Coefficient
PPL_PROTO((ppl_Coefficient_t dst, ppl_const_Coefficient_t src));

/*! \brief
  Invalidates the handle \p c: this makes sure the corresponding
  resources will eventually be released.
*/
int
ppl_delete_Coefficient PPL_PROTO((ppl_const_Coefficient_t c));

/*! \brief
  Sets the value of the GMP integer \p z to the value of \p c.
*/
int
ppl_Coefficient_to_mpz_t PPL_PROTO((ppl_const_Coefficient_t c, mpz_t z));

/*! \brief
  Returns a positive integer if \p c is well formed, i.e., if it
  satisfies all its implementation invariants; returns 0 and perhaps
  makes some noise if \p c is broken.  Useful for debugging purposes.
*/
int
ppl_Coefficient_OK PPL_PROTO((ppl_const_Coefficient_t c));

/*! \brief
  Returns a positive integer if coefficients are bounded; returns 0
  otherwise.
*/
int
ppl_Coefficient_is_bounded PPL_PROTO((void));

/*! \brief
  Returns a positive integer if coefficients are bounded, in which case
  \p min is set to their minimum value; returns 0 otherwise.
*/
int
ppl_Coefficient_min PPL_PROTO((mpz_t min));

/*! \brief
  Returns a positive integer if coefficients are bounded, in which case
  \p max is set to their maximum value; returns 0 otherwise.
*/
int
ppl_Coefficient_max PPL_PROTO((mpz_t max));

/*@}*/ /* Functions Related to Coefficients */

/*! \name Functions Related to Linear Expressions */
/*@{*/

/*! \brief
  Creates a new linear expression corresponding to the constant 0 in a
  zero-dimensional space; writes a handle for the new linear
  expression at address \p ple.
*/
int
ppl_new_Linear_Expression PPL_PROTO((ppl_Linear_Expression_t* ple));

/*! \brief
  Creates a new linear expression corresponding to the constant 0 in a
  <TT>d</TT>-dimensional space; writes a handle for the new linear
  expression at address \p ple.
*/
int
ppl_new_Linear_Expression_with_dimension
PPL_PROTO((ppl_Linear_Expression_t* ple, ppl_dimension_type d));

/*! \brief
  Builds a linear expression that is a copy of \p le; writes a handle
  for the newly created linear expression at address \p ple.
*/
int
ppl_new_Linear_Expression_from_Linear_Expression
PPL_PROTO((ppl_Linear_Expression_t* ple, ppl_const_Linear_Expression_t le));

/*! \brief
  Builds a linear expression corresponding to constraint \p c;
  writes a handle for the newly created linear expression at address \p ple.
*/
int
ppl_new_Linear_Expression_from_Constraint
PPL_PROTO((ppl_Linear_Expression_t* ple, ppl_const_Constraint_t c));

/*! \brief
  Builds a linear expression corresponding to generator \p g;
  writes a handle for the newly created linear expression at address \p ple.
*/
int
ppl_new_Linear_Expression_from_Generator
PPL_PROTO((ppl_Linear_Expression_t* ple, ppl_const_Generator_t g));

/*! \brief
  Invalidates the handle \p le: this makes sure the corresponding
  resources will eventually be released.
*/
int
ppl_delete_Linear_Expression PPL_PROTO((ppl_const_Linear_Expression_t le));

/*! \brief
  Assigns a copy of the linear expression \p src to \p dst.
*/
int
ppl_assign_Linear_Expression_from_Linear_Expression
PPL_PROTO((ppl_Linear_Expression_t dst, ppl_const_Linear_Expression_t src));

/*! \brief
  Adds \p n to the coefficient of variable \p var in the linear
  expression \p le.  The space dimension is set to be the maximum
  between \p var + 1 and the old space dimension.
*/
int
ppl_Linear_Expression_add_to_coefficient
PPL_PROTO((ppl_Linear_Expression_t le,
	   ppl_dimension_type var,
	   ppl_const_Coefficient_t n));

/*! \brief
  Adds \p n to the inhomogeneous term of the linear expression
  \p le.
*/
int
ppl_Linear_Expression_add_to_inhomogeneous
PPL_PROTO((ppl_Linear_Expression_t le, ppl_const_Coefficient_t n));

/*! \brief
  Adds the linear expression \p src to \p dst.
*/
int
ppl_add_Linear_Expression_to_Linear_Expression
PPL_PROTO((ppl_Linear_Expression_t dst, ppl_const_Linear_Expression_t src));

/*! \brief
  Subtracts the linear expression \p src from \p dst.
*/
int
ppl_subtract_Linear_Expression_from_Linear_Expression
PPL_PROTO((ppl_Linear_Expression_t dst, ppl_const_Linear_Expression_t src));

/*! \brief
  Multiply the linear expression \p dst by \p n.
*/
int
ppl_multiply_Linear_Expression_by_Coefficient
PPL_PROTO((ppl_Linear_Expression_t le, ppl_const_Coefficient_t n));

/*! \brief
  Writes to \p m the space dimension of \p le.
*/
int
ppl_Linear_Expression_space_dimension
PPL_PROTO((ppl_const_Linear_Expression_t le, ppl_dimension_type* m));

/*! \brief
  Copies into \p n the coefficient of variable \p var in
  the linear expression \p le.
*/
int
ppl_Linear_Expression_coefficient PPL_PROTO((ppl_const_Linear_Expression_t le,
					     ppl_dimension_type var,
					     ppl_Coefficient_t n));

/*! \brief
  Copies into \p n the inhomogeneous term of linear expression \p le.
*/
int
ppl_Linear_Expression_inhomogeneous_term
PPL_PROTO((ppl_const_Linear_Expression_t le, ppl_Coefficient_t n));

/*! \brief
  Returns a positive integer if \p le is well formed, i.e., if it
  satisfies all its implementation invariants; returns 0 and perhaps
  makes some noise if \p le is broken.  Useful for debugging purposes.
*/
int
ppl_Linear_Expression_OK PPL_PROTO((ppl_const_Linear_Expression_t le));

/*@}*/ /* Functions Related to Linear Expressions */

/*! \brief
  Describes the relations represented by a constraint.
*/
enum ppl_enum_Constraint_Type {
  /*! The constraint is of the form \f$e < 0\f$. */
  PPL_CONSTRAINT_TYPE_LESS_THAN,
  /*! The constraint is of the form \f$e \leq 0\f$. */
  PPL_CONSTRAINT_TYPE_LESS_THAN_OR_EQUAL,
  /*! The constraint is of the form \f$e = 0\f$. */
  PPL_CONSTRAINT_TYPE_EQUAL,
  /*! The constraint is of the form \f$e \geq 0\f$. */
  PPL_CONSTRAINT_TYPE_GREATER_THAN_OR_EQUAL,
  /*! The constraint is of the form \f$e > 0\f$. */
  PPL_CONSTRAINT_TYPE_GREATER_THAN
};


/*! \name Functions Related to Constraints */
/*@{*/

/*! \brief
  Creates the new constraint `\p le \p rel 0' and writes a handle for
  it at address \p pc.  The space dimension of the new constraint is
  equal to the space dimension of \p le.
*/
int
ppl_new_Constraint PPL_PROTO((ppl_Constraint_t* pc,
			      ppl_const_Linear_Expression_t le,
			      enum ppl_enum_Constraint_Type rel));

/*! \brief
  Creates the unsatisfiable (zero-dimension space) constraint \f$0 = 1\f$
  and writes a handle for it at address \p pc.
*/
int
ppl_new_Constraint_zero_dim_false PPL_PROTO((ppl_Constraint_t* pc));

/*! \brief
  Creates the true (zero-dimension space) constraint \f$0 \leq 1\f$,
  also known as <EM>positivity constraint</EM>.
  A handle for the newly created constraint is written at address \p pc.
*/
int
ppl_new_Constraint_zero_dim_positivity PPL_PROTO((ppl_Constraint_t* pc));

/*! \brief
  Builds a constraint that is a copy of \p c; writes a handle
  for the newly created constraint at address \p pc.
*/
int
ppl_new_Constraint_from_Constraint PPL_PROTO((ppl_Constraint_t* pc,
					      ppl_const_Constraint_t c));

/*! \brief
  Invalidates the handle \p c: this makes sure the corresponding
  resources will eventually be released.
*/
int
ppl_delete_Constraint PPL_PROTO((ppl_const_Constraint_t c));

/*! \brief
  Assigns a copy of the constraint \p src to \p dst.
*/
int
ppl_assign_Constraint_from_Constraint PPL_PROTO((ppl_Constraint_t dst,
						 ppl_const_Constraint_t src));

/*! \brief
  Writes to \p m the space dimension of \p c.
*/
int
ppl_Constraint_space_dimension PPL_PROTO((ppl_const_Constraint_t c,
					  ppl_dimension_type* m));

/*! \brief
  Returns the type of constraint \p c.
*/
int
ppl_Constraint_type PPL_PROTO((ppl_const_Constraint_t c));

/*! \brief
  Copies into \p n the coefficient of variable \p var in
  constraint \p c.
*/
int
ppl_Constraint_coefficient PPL_PROTO((ppl_const_Constraint_t c,
				      ppl_dimension_type var,
				      ppl_Coefficient_t n));

/*! \brief
  Copies into \p n the inhomogeneous term of constraint \p c.
*/
int
ppl_Constraint_inhomogeneous_term PPL_PROTO((ppl_const_Constraint_t c,
					     ppl_Coefficient_t n));

/*! \brief
  Returns a positive integer if \p c is well formed, i.e., if it
  satisfies all its implementation invariants; returns 0 and perhaps
  makes some noise if \p c is broken.  Useful for debugging purposes.
*/
int
ppl_Constraint_OK PPL_PROTO((ppl_const_Constraint_t c));

/*@}*/ /* Functions Related to Constraints */

/*! \name Functions Related to Constraint Systems */
/*@{*/

/*! \brief
  Builds an empty system of constraints and writes a handle to it at
  address \p pcs.
*/
int
ppl_new_Constraint_System PPL_PROTO((ppl_Constraint_System_t* pcs));

/*! \brief
  Builds a zero-dimensional, unsatisfiable constraint system and
  writes a handle to it at address \p pcs.
*/
int
ppl_new_Constraint_System_zero_dim_empty
PPL_PROTO((ppl_Constraint_System_t* pcs));

/*! \brief
  Builds the singleton constraint system containing only a copy of
  constraint \p c; writes a handle for the newly created system at
  address \p pcs.
*/
int
ppl_new_Constraint_System_from_Constraint
PPL_PROTO((ppl_Constraint_System_t* pcs, ppl_const_Constraint_t c));

/*! \brief
  Builds a constraint system that is a copy of \p cs; writes a handle
  for the newly created system at address \p pcs.
*/
int
ppl_new_Constraint_System_from_Constraint_System
PPL_PROTO((ppl_Constraint_System_t* pcs, ppl_const_Constraint_System_t cs));

/*! \brief
  Invalidates the handle \p cs: this makes sure the corresponding
  resources will eventually be released.
*/
int
ppl_delete_Constraint_System PPL_PROTO((ppl_const_Constraint_System_t cs));

/*! \brief
  Assigns a copy of the constraint system \p src to \p dst.
*/
int
ppl_assign_Constraint_System_from_Constraint_System
PPL_PROTO((ppl_Constraint_System_t dst, ppl_const_Constraint_System_t src));

/*! \brief
  Writes to \p m the dimension of the vector space enclosing \p cs.
*/
int
ppl_Constraint_System_space_dimension
PPL_PROTO((ppl_const_Constraint_System_t cs, ppl_dimension_type* m));

/*! \brief
  Returns a positive integer if \p cs contains any (non-trivial) strict
  inequality; returns 0 otherwise.
*/
int
ppl_Constraint_System_has_strict_inequalities
PPL_PROTO((ppl_const_Constraint_System_t cs));

/*! \brief
  Removes all the constraints from the constraint system \p cs
  and sets its space dimension to 0.
*/
int
ppl_Constraint_System_clear PPL_PROTO((ppl_Constraint_System_t cs));

/*! \brief
  Inserts a copy of the constraint \p c into \p cs; the space
  dimension is increased, if necessary.
*/
int
ppl_Constraint_System_insert_Constraint PPL_PROTO((ppl_Constraint_System_t cs,
						   ppl_const_Constraint_t c));

/*! \brief
  Returns a positive integer if \p cs is well formed, i.e., if it
  satisfies all its implementation invariants; returns 0 and perhaps
  makes some noise if \p cs is broken.  Useful for debugging purposes.
*/
int
ppl_Constraint_System_OK PPL_PROTO((ppl_const_Constraint_System_t c));


/*! \brief
  Builds a new `const iterator' and writes a handle to it at address
  \p pcit.
*/
int
ppl_new_Constraint_System_const_iterator
PPL_PROTO((ppl_Constraint_System_const_iterator_t* pcit));

/*! \brief
  Builds a const iterator that is a copy of \p cit; writes an
  handle for the newly created const iterator at address \p pcit.
*/
int
ppl_new_Constraint_System_const_iterator_from_Constraint_System_const_iterator
PPL_PROTO((ppl_Constraint_System_const_iterator_t* pcit,
	   ppl_const_Constraint_System_const_iterator_t cit));

/*! \brief
  Invalidates the handle \p cit: this makes sure the corresponding
  resources will eventually be released.
*/
int
ppl_delete_Constraint_System_const_iterator
PPL_PROTO((ppl_const_Constraint_System_const_iterator_t cit));

/*! \brief
  Assigns a copy of the const iterator \p src to \p dst.
*/
int
ppl_assign_Constraint_System_const_iterator_from_Constraint_System_const_iterator
PPL_PROTO((ppl_Constraint_System_const_iterator_t dst,
	   ppl_const_Constraint_System_const_iterator_t src));

/*! \brief
  Assigns to \p cit a const iterator "pointing" to the beginning of
  the constraint system \p cs.
*/
int
ppl_Constraint_System_begin
PPL_PROTO((ppl_const_Constraint_System_t cs,
	   ppl_Constraint_System_const_iterator_t cit));

/*! \brief
  Assigns to \p cit a const iterator "pointing" past the end of the
  constraint system \p cs.
*/
int
ppl_Constraint_System_end
PPL_PROTO((ppl_const_Constraint_System_t cs,
	   ppl_Constraint_System_const_iterator_t cit));

/*! \brief
  Dereference \p cit writing a const handle to the resulting
  constraint at address \p pc.
*/
int
ppl_Constraint_System_const_iterator_dereference
PPL_PROTO((ppl_const_Constraint_System_const_iterator_t cit,
	   ppl_const_Constraint_t* pc));

/*! \brief
  Increment \p cit so that it "points" to the next constraint.
*/
int
ppl_Constraint_System_const_iterator_increment
PPL_PROTO((ppl_Constraint_System_const_iterator_t cit));

/*! \brief
  Returns a positive integer if the iterators corresponding to \p x and
  \p y are equal; returns 0 if they are different.
*/
int
ppl_Constraint_System_const_iterator_equal_test
PPL_PROTO((ppl_const_Constraint_System_const_iterator_t x,
	   ppl_const_Constraint_System_const_iterator_t y));

/*@}*/ /* Functions Related to Constraint Systems */

/*! \brief
  Describes the different kinds of generators.
*/
enum ppl_enum_Generator_Type {
  /*! The generator is a line. */
  PPL_GENERATOR_TYPE_LINE,
  /*! The generator is a ray. */
  PPL_GENERATOR_TYPE_RAY,
  /*! The generator is a point. */
  PPL_GENERATOR_TYPE_POINT,
  /*! The generator is a closure point. */
  PPL_GENERATOR_TYPE_CLOSURE_POINT
};


/*! \name Functions Related to Generators */
/*@{*/

/*! \brief
  Creates a new generator of direction \p le and type \p t.  If the
  generator to be created is a point or a closure point, the divisor
  \p d is applied to \p le.  For other types of generators \p d is
  simply disregarded.  A handle for the new generator is written at
  address \p pg.  The space dimension of the new generator is equal to
  the space dimension of \p le.
*/
int
ppl_new_Generator PPL_PROTO((ppl_Generator_t* pg,
			     ppl_const_Linear_Expression_t le,
			     enum ppl_enum_Generator_Type t,
			     ppl_const_Coefficient_t d));

/*! \brief
  Creates the point that is the origin of the zero-dimensional space
  \f$\Rset^0\f$.  Writes a handle for the new generator at address
  \p pg.
*/
int
ppl_new_Generator_zero_dim_point PPL_PROTO((ppl_Generator_t* pg));

/*! \brief
  Creates, as a closure point, the point that is the origin of the
  zero-dimensional space \f$\Rset^0\f$.  Writes a handle for the new
  generator at address \p pg.
*/
int
ppl_new_Generator_zero_dim_closure_point PPL_PROTO((ppl_Generator_t* pg));

/*! \brief
  Builds a generator that is a copy of \p g; writes a handle
  for the newly created generator at address \p pg.
*/
int
ppl_new_Generator_from_Generator PPL_PROTO((ppl_Generator_t* pg,
					    ppl_const_Generator_t g));

/*! \brief
  Invalidates the handle \p g: this makes sure the corresponding
  resources will eventually be released.
*/
int
ppl_delete_Generator PPL_PROTO((ppl_const_Generator_t g));

/*! \brief
  Assigns a copy of the generator \p src to \p dst.
*/
int
ppl_assign_Generator_from_Generator PPL_PROTO((ppl_Generator_t dst,
					       ppl_const_Generator_t src));

/*! \brief
  Writes to \p m the space dimension of \p g.
*/
int
ppl_Generator_space_dimension PPL_PROTO((ppl_const_Generator_t g,
					 ppl_dimension_type* m));

/*! \brief
  Returns the type of generator \p g.
*/
int
ppl_Generator_type PPL_PROTO((ppl_const_Generator_t g));

/*! \brief
  Copies into \p n the coefficient of variable \p var in
  generator \p g.
*/
int
ppl_Generator_coefficient PPL_PROTO((ppl_const_Generator_t g,
				     ppl_dimension_type var,
				     ppl_Coefficient_t n));

/*! \brief
  If \p g is a point or a closure point assigns its divisor to \p n.
*/
int
ppl_Generator_divisor PPL_PROTO((ppl_const_Generator_t g,
				 ppl_Coefficient_t n));

/*! \brief
  Returns a positive integer if \p g is well formed, i.e., if it
  satisfies all its implementation invariants; returns 0 and perhaps
  makes some noise if \p g is broken.  Useful for debugging purposes.
*/
int
ppl_Generator_OK PPL_PROTO((ppl_const_Generator_t g));

/*@}*/ /* Functions Related to Generators */

/*! \name Functions Related to Generator Systems */
/*@{*/

/*! \brief
  Builds an empty system of generators and writes a handle to it at
  address \p pgs.
*/
int
ppl_new_Generator_System PPL_PROTO((ppl_Generator_System_t* pgs));

/*
  Creates the universe zero-dimensional system of generators (i.e.,
  containing the origin only).  Writes a handle to the new system at
  address \p pgs.
*/
int
ppl_new_Generator_System_zero_dim_univ
PPL_PROTO((ppl_Generator_System_t* pgs));

/*! \brief
  Builds the singleton generator system containing only a copy of
  generator \p g; writes a handle for the newly created system at
  address \p pgs.
*/
int
ppl_new_Generator_System_from_Generator PPL_PROTO((ppl_Generator_System_t* pgs,
						   ppl_const_Generator_t g));

/*! \brief
  Builds a generator system that is a copy of \p gs; writes a handle
  for the newly created system at address \p pgs.
*/
int
ppl_new_Generator_System_from_Generator_System
PPL_PROTO((ppl_Generator_System_t* pgs, ppl_const_Generator_System_t gs));

/*! \brief
  Invalidates the handle \p gs: this makes sure the corresponding
  resources will eventually be released.
*/
int
ppl_delete_Generator_System PPL_PROTO((ppl_const_Generator_System_t gs));

/*! \brief
  Assigns a copy of the generator system \p src to \p dst.
*/
int
ppl_assign_Generator_System_from_Generator_System
PPL_PROTO((ppl_Generator_System_t dst, ppl_const_Generator_System_t src));

/*! \brief
  Writes to \p m the dimension of the vector space enclosing \p gs.
*/
int
ppl_Generator_System_space_dimension
PPL_PROTO((ppl_const_Generator_System_t gs, ppl_dimension_type* m));

/*! \brief
  Removes all the generators from the generator system \p gs
  and sets its space dimension to 0.
*/
int
ppl_Generator_System_clear PPL_PROTO((ppl_Generator_System_t gs));

/*! \brief
  Inserts a copy of the generator \p g into \p gs; the space
  dimension is increased, if necessary.
*/
int
ppl_Generator_System_insert_Generator PPL_PROTO((ppl_Generator_System_t gs,
						 ppl_const_Generator_t g));

/*! \brief
  Returns a positive integer if \p gs is well formed, i.e., if it
  satisfies all its implementation invariants; returns 0 and perhaps
  makes some noise if \p gs is broken.  Useful for debugging purposes.
*/
int
ppl_Generator_System_OK PPL_PROTO((ppl_const_Generator_System_t c));


/*! \brief
  Builds a new `const iterator' and writes a handle to it at address
  \p pgit.
*/
int
ppl_new_Generator_System_const_iterator
PPL_PROTO((ppl_Generator_System_const_iterator_t* pgit));

/*! \brief
  Builds a const iterator that is a copy of \p git; writes an
  handle for the newly created const iterator at address \p pgit.
*/
int
ppl_new_Generator_System_const_iterator_from_Generator_System_const_iterator
PPL_PROTO((ppl_Generator_System_const_iterator_t* pgit,
	   ppl_const_Generator_System_const_iterator_t git));

/*! \brief
  Invalidates the handle \p git: this makes sure the corresponding
  resources will eventually be released.
*/
int
ppl_delete_Generator_System_const_iterator
PPL_PROTO((ppl_const_Generator_System_const_iterator_t git));

/*! \brief
  Assigns a copy of the const iterator \p src to \p dst.
*/
int
ppl_assign_Generator_System_const_iterator_from_Generator_System_const_iterator
PPL_PROTO((ppl_Generator_System_const_iterator_t dst,
	   ppl_const_Generator_System_const_iterator_t src));

/*! \brief
  Assigns to \p git a const iterator "pointing" to the beginning of
  the generator system \p gs.
*/
int
ppl_Generator_System_begin
PPL_PROTO((ppl_const_Generator_System_t gs,
	   ppl_Generator_System_const_iterator_t git));

/*! \brief
  Assigns to \p git a const iterator "pointing" past the end of the
  generator system \p gs.
*/
int
ppl_Generator_System_end
PPL_PROTO((ppl_const_Generator_System_t gs,
	   ppl_Generator_System_const_iterator_t git));

/*! \brief
  Dereference \p git writing a const handle to the resulting
  generator at address \p pg.
*/
int
ppl_Generator_System_const_iterator_dereference
PPL_PROTO((ppl_const_Generator_System_const_iterator_t git,
	   ppl_const_Generator_t* pg));

/*! \brief
  Increment \p git so that it "points" to the next generator.
*/
int
ppl_Generator_System_const_iterator_increment
PPL_PROTO((ppl_Generator_System_const_iterator_t git));

/*! \brief
  Returns a positive integer if the iterators corresponding to \p x and
  \p y are equal; returns 0 if they are different.
*/
int
ppl_Generator_System_const_iterator_equal_test
PPL_PROTO((ppl_const_Generator_System_const_iterator_t x,
	   ppl_const_Generator_System_const_iterator_t y));

/*@}*/ /* Functions Related to Generator Systems */

/*! \brief
  Code of the worst-case polynomial complexity class.
*/
extern unsigned int PPL_COMPLEXITY_CLASS_POLYNOMIAL;

/*! \brief
  Code of the worst-case exponential but typically polynomial
  complexity class.
*/
extern unsigned int PPL_COMPLEXITY_CLASS_SIMPLEX;

/*! \brief
  Code of the universal complexity class.
*/
extern unsigned int PPL_COMPLEXITY_CLASS_ANY;

/*! \brief
  Code of the "unfeasible LP problem" status.
*/
extern int PPL_LP_PROBLEM_STATUS_UNFEASIBLE;

/*! \brief
  Code of the "unbounded LP problem" status.
*/
extern int PPL_LP_PROBLEM_STATUS_UNBOUNDED;

/*! \brief
  Code of the "optimized LP problem" status.
*/
extern int PPL_LP_PROBLEM_STATUS_OPTIMIZED;

/*! \brief
  Code of the "maximization" optimization mode.
*/
extern int PPL_LP_PROBLEM_MAXIMIZATION;

/*! \brief
  Code of the "minimization" optimization mode.
*/
extern int PPL_LP_PROBLEM_MINIMIZATION;

/*! \brief
  Individual bit saying that the polyhedron and the set of points
  satisfying the constraint are disjoint.
*/
extern unsigned int PPL_POLY_CON_RELATION_IS_DISJOINT;

/*! \brief
  Individual bit saying that the polyhedron intersects the set of
  points satisfying the constraint, but it is not included in it.
*/
extern unsigned int PPL_POLY_CON_RELATION_STRICTLY_INTERSECTS;

/*! \brief
  Individual bit saying that the polyhedron is included in the set of
  points satisfying the constraint.
*/
extern unsigned int PPL_POLY_CON_RELATION_IS_INCLUDED;

/*! \brief
  Individual bit saying that the polyhedron is included in the set of
  points saturating the constraint.
*/
extern unsigned int PPL_POLY_CON_RELATION_SATURATES;

/*! \brief
  Individual bit saying that adding the generator would not change the
  polyhedron.
*/
extern unsigned int PPL_POLY_GEN_RELATION_SUBSUMES;

/*! \name Functions Related to Polyhedra */
/*@{*/

/*! \brief
  Builds a universe C polyhedron of dimension \p d and writes an
  handle to it at address \p pph.
*/
int
ppl_new_C_Polyhedron_from_dimension PPL_PROTO((ppl_Polyhedron_t* pph,
					       ppl_dimension_type d));

/*! \brief
  Builds a universe NNC polyhedron of dimension \p d and writes an
  handle to it at address \p pph.
*/
int
ppl_new_NNC_Polyhedron_from_dimension PPL_PROTO((ppl_Polyhedron_t* pph,
						 ppl_dimension_type d));

/*! \brief
  Builds an empty C polyhedron of space dimension \p d and writes an
  handle to it at address \p pph.
*/
int
ppl_new_C_Polyhedron_empty_from_dimension PPL_PROTO((ppl_Polyhedron_t* pph,
						     ppl_dimension_type d));

/*! \brief
  Builds an empty NNC polyhedron of space dimension \p d and writes an
  handle to it at address \p pph.
*/
int
ppl_new_NNC_Polyhedron_empty_from_dimension PPL_PROTO((ppl_Polyhedron_t* pph,
						       ppl_dimension_type d));

/*! \brief
  Builds a C polyhedron that is a copy of \p ph; writes a handle
  for the newly created polyhedron at address \p pph.
*/
int
ppl_new_C_Polyhedron_from_C_Polyhedron PPL_PROTO((ppl_Polyhedron_t* pph,
						  ppl_const_Polyhedron_t ph));

/*! \brief
  Builds a C polyhedron that is a copy of of the NNC polyhedron \p ph;
  writes a handle for the newly created polyhedron at address \p pph.
*/
int
ppl_new_C_Polyhedron_from_NNC_Polyhedron
PPL_PROTO((ppl_Polyhedron_t* pph, ppl_const_Polyhedron_t ph));

/*! \brief
  Builds an NNC polyhedron that is a copy of the C polyhedron \p ph;
  writes a handle for the newly created polyhedron at address \p pph.
*/
int
ppl_new_NNC_Polyhedron_from_C_Polyhedron
PPL_PROTO((ppl_Polyhedron_t* pph, ppl_const_Polyhedron_t ph));

/*! \brief
  Builds an NNC polyhedron that is a copy of \p ph; writes a handle
  for the newly created polyhedron at address \p pph.
*/
int
ppl_new_NNC_Polyhedron_from_NNC_Polyhedron
PPL_PROTO((ppl_Polyhedron_t* pph, ppl_const_Polyhedron_t ph));

/*! \brief
  Builds a new C polyhedron from the system of constraints
  \p cs and writes a handle for the newly created polyhedron at
  address \p pph.

  The new polyhedron will inherit the space dimension of \p cs.
*/
int
ppl_new_C_Polyhedron_from_Constraint_System
PPL_PROTO((ppl_Polyhedron_t* pph, ppl_const_Constraint_System_t cs));

/*! \brief
  Builds a new C polyhedron recycling the system of constraints
  \p cs and writes a handle for the newly created polyhedron at
  address \p pph.

  Since \p cs will be <EM>the</EM> system of constraints of the new
  polyhedron, the space dimension is also inherited.

  \warning
  This function modifies the constraint system referenced by \p cs:
  upon return, no assumption can be made on its value.
*/
int
ppl_new_C_Polyhedron_recycle_Constraint_System
PPL_PROTO((ppl_Polyhedron_t* pph, ppl_Constraint_System_t cs));

/*! \brief
  Builds a new NNC polyhedron from the system of constraints
  \p cs and writes a handle for the newly created polyhedron at
  address \p pph.

  The new polyhedron will inherit the space dimension of \p cs.
*/
int
ppl_new_NNC_Polyhedron_from_Constraint_System
PPL_PROTO((ppl_Polyhedron_t* pph, ppl_const_Constraint_System_t cs));

/*! \brief
  Builds a new NNC polyhedron recycling the system of constraints
  \p cs and writes a handle for the newly created polyhedron at
  address \p pph.

  Since \p cs will be <EM>the</EM> system of constraints of the new
  polyhedron, the space dimension is also inherited.

  \warning
  This function modifies the constraint system referenced by \p cs:
  upon return, no assumption can be made on its value.
*/
int
ppl_new_NNC_Polyhedron_recycle_Constraint_System
PPL_PROTO((ppl_Polyhedron_t* pph, ppl_Constraint_System_t cs));

/*! \brief
  Builds a new C polyhedron from the system of generators
  \p gs and writes a handle for the newly created polyhedron at
  address \p pph.

  The new polyhedron will inherit the space dimension of \p gs.
*/
int
ppl_new_C_Polyhedron_from_Generator_System
PPL_PROTO((ppl_Polyhedron_t* pph, ppl_const_Generator_System_t gs));

/*! \brief
  Builds a new C polyhedron recycling the system of generators
  \p gs and writes a handle for the newly created polyhedron at
  address \p pph.

  Since \p gs will be <EM>the</EM> system of generators of the new
  polyhedron, the space dimension is also inherited.

  \warning
  This function modifies the generator system referenced by \p gs:
  upon return, no assumption can be made on its value.
*/
int
ppl_new_C_Polyhedron_recycle_Generator_System
PPL_PROTO((ppl_Polyhedron_t* pph, ppl_Generator_System_t gs));

/*! \brief
  Builds a new NNC polyhedron from the system of generators
  \p gs and writes a handle for the newly created polyhedron at
  address \p pph.

  The new polyhedron will inherit the space dimension of \p gs.
*/
int
ppl_new_NNC_Polyhedron_from_Generator_System
PPL_PROTO((ppl_Polyhedron_t* pph, ppl_const_Generator_System_t gs));

/*! \brief
  Builds a new NNC polyhedron recycling the system of generators
  \p gs and writes a handle for the newly created polyhedron at
  address \p pph.

  Since \p gs will be <EM>the</EM> system of generators of the new
  polyhedron, the space dimension is also inherited.

  \warning
  This function modifies the generator system referenced by \p gs:
  upon return, no assumption can be made on its value.
*/
int
ppl_new_NNC_Polyhedron_recycle_Generator_System
PPL_PROTO((ppl_Polyhedron_t* pph, ppl_Generator_System_t gs));

/*! \brief
  Builds a new C polyhedron corresponding to an interval-based
  bounding box, writing a handle for the newly created polyhedron at
  address \p pph.

  If an interval of the bounding box is provided with any finite
  but open bound, then the polyhedron is not built and the value
  <CODE>PPL_ERROR_INVALID_ARGUMENT</CODE> is returned.
  The bounding box is accessed by using the following functions,
  passed as arguments:
    \code
      ppl_dimension_type space_dimension()
    \endcode
    returns the dimension of the vector space enclosing the polyhedron
    represented by the bounding box.
    \code
      int is_empty()
    \endcode
    returns 0 if and only if the bounding box describes a non-empty set.
    The function <CODE>is_empty()</CODE> will always be called before the
    other functions. However, if <CODE>is_empty()</CODE> does not
    return 0, none of the functions below will be called.
    \code
      int get_lower_bound(ppl_dimension_type k, int closed,
                          ppl_Coefficient_t n, ppl_Coefficient_t d)
    \endcode
    Let \f$I\f$ the interval corresponding to the <CODE>k</CODE>-th
    space dimension.  If \f$I\f$ is not bounded from below, simply return 0.
    Otherwise, set <CODE>closed</CODE>, <CODE>n</CODE> and
    <CODE>d</CODE> as follows: <CODE>closed</CODE> is set to 0 if the
    lower boundary of \f$I\f$ is open and is set to a value different
    from zero 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
      int get_upper_bound(ppl_dimension_type k, int closed,
                          ppl_Coefficient_t n, ppl_Coefficient_t d)
    \endcode
    Let \f$I\f$ the interval corresponding to the <CODE>k</CODE>-th
    space dimension.  If \f$I\f$ is not bounded from above, simply return 0.
    Otherwise, set <CODE>closed</CODE>, <CODE>n</CODE> and
    <CODE>d</CODE> as follows: <CODE>closed</CODE> is set to 0 if the
    upper boundary of \f$I\f$ is open and is set to a value different
    from 0 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$.
*/
int
ppl_new_C_Polyhedron_from_bounding_box
PPL_PROTO((ppl_Polyhedron_t* pph,
	   ppl_dimension_type (*space_dimension)(void),
	   int (*is_empty)(void),
	   int (*get_lower_bound)(ppl_dimension_type k, int closed,
				  ppl_Coefficient_t n,
				  ppl_Coefficient_t d),
	   int (*get_upper_bound)(ppl_dimension_type k, int closed,
				  ppl_Coefficient_t n,
				  ppl_Coefficient_t d)));

/*! \brief
  Builds a new NNC polyhedron corresponding to an interval-based
  bounding box, writing a handle for the newly created polyhedron at
  address \p pph.

  The bounding box is accessed by using the following functions,
  passed as arguments:
    \code
      ppl_dimension_type space_dimension()
    \endcode
    returns the dimension of the vector space enclosing the polyhedron
    represented by the bounding box.
    \code
      int is_empty()
    \endcode
    returns 0 if and only if the bounding box describes a non-empty set.
    The function <CODE>is_empty()</CODE> will always be called before the
    other functions. However, if <CODE>is_empty()</CODE> does not
    return 0, none of the functions below will be called.
    \code
      int get_lower_bound(ppl_dimension_type k, int closed,
                          ppl_Coefficient_t n, ppl_Coefficient_t d)
    \endcode
    Let \f$I\f$ the interval corresponding to the <CODE>k</CODE>-th
    space dimension.  If \f$I\f$ is not bounded from below, simply return 0.
    Otherwise, set <CODE>closed</CODE>, <CODE>n</CODE> and
    <CODE>d</CODE> as follows: <CODE>closed</CODE> is set to 0 if the
    lower boundary of \f$I\f$ is open and is set to a value different
    from zero 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
      int get_upper_bound(ppl_dimension_type k, int closed,
                          ppl_Coefficient_t n, ppl_Coefficient_t d)
    \endcode
    Let \f$I\f$ the interval corresponding to the <CODE>k</CODE>-th
    space dimension.  If \f$I\f$ is not bounded from above, simply return 0.
    Otherwise, set <CODE>closed</CODE>, <CODE>n</CODE> and
    <CODE>d</CODE> as follows: <CODE>closed</CODE> is set to 0 if the
    upper boundary of \f$I\f$ is open and is set to a value different
    from 0 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$.
*/
int
ppl_new_NNC_Polyhedron_from_bounding_box
PPL_PROTO((ppl_Polyhedron_t* pph,
	   ppl_dimension_type (*space_dimension)(void),
	   int (*is_empty)(void),
	   int (*get_lower_bound)(ppl_dimension_type k, int closed,
				  ppl_Coefficient_t n,
				  ppl_Coefficient_t d),
	   int (*get_upper_bound)(ppl_dimension_type k, int closed,
				  ppl_Coefficient_t n,
				  ppl_Coefficient_t d)));

/*! \brief
  Assigns a copy of the C polyhedron \p src to the C polyhedron \p dst.
*/
int
ppl_assign_C_Polyhedron_from_C_Polyhedron
PPL_PROTO((ppl_Polyhedron_t dst, ppl_const_Polyhedron_t src));

/*! \brief
  Assigns a copy of the NNC polyhedron \p src to the NNC
  polyhedron \p dst.
*/
int
ppl_assign_NNC_Polyhedron_from_NNC_Polyhedron
PPL_PROTO((ppl_Polyhedron_t dst, ppl_const_Polyhedron_t src));

/*! \brief
  Invalidates the handle \p ph: this makes sure the corresponding
  resources will eventually be released.
*/
int
ppl_delete_Polyhedron PPL_PROTO((ppl_const_Polyhedron_t ph));

/*! \brief
  Writes to \p m the dimension of the vector space enclosing \p ph.
*/
int
ppl_Polyhedron_space_dimension PPL_PROTO((ppl_const_Polyhedron_t ph,
					  ppl_dimension_type* m));

/*! \brief
  Writes to \p m the affine dimension of \p ph (not to be confused with the
  dimension of its enclosing vector space) or 0, if \p ph is empty.
*/
int
ppl_Polyhedron_affine_dimension PPL_PROTO((ppl_const_Polyhedron_t ph));

/*! \brief
  Writes a const handle to the constraint system defining the
  polyhedron \p ph at address \p pcs.
*/
int
ppl_Polyhedron_constraints PPL_PROTO((ppl_const_Polyhedron_t ph,
				      ppl_const_Constraint_System_t* pcs));

/*! \brief
  Writes a const handle to the minimized constraint system defining the
  polyhedron \p ph at address \p pcs.
*/
int
ppl_Polyhedron_minimized_constraints
PPL_PROTO((ppl_const_Polyhedron_t ph, ppl_const_Constraint_System_t* pcs));

/*! \brief
  Writes a const handle to the generator system defining the
  polyhedron \p ph at address \p pgs.
*/
int
ppl_Polyhedron_generators PPL_PROTO((ppl_const_Polyhedron_t ph,
				     ppl_const_Generator_System_t* pgs));

/*! \brief
  Writes a const handle to the minimized generator system defining the
  polyhedron \p ph at address \p pgs.
*/
int
ppl_Polyhedron_minimized_generators
PPL_PROTO((ppl_const_Polyhedron_t ph, ppl_const_Generator_System_t* pgs));

/*! \brief
  Checks the relation between the polyhedron \p ph and the constraint \p c.

  If successful, returns a non-negative integer that is
  obtained as the bitwise or of the bits (chosen among
  PPL_POLY_CON_RELATION_IS_DISJOINT
  PPL_POLY_CON_RELATION_STRICTLY_INTERSECTS,
  PPL_POLY_CON_RELATION_IS_INCLUDED, and
  PPL_POLY_CON_RELATION_SATURATES) that describe the relation between
  \p ph and \p c.
*/
int
ppl_Polyhedron_relation_with_Constraint PPL_PROTO((ppl_const_Polyhedron_t ph,
						   ppl_const_Constraint_t c));

/*! \brief
  Checks the relation between the polyhedron \p ph and the generator \p g.

  If successful, returns a non-negative integer that is
  obtained as the bitwise or of the bits (only
  PPL_POLY_GEN_RELATION_SUBSUMES, at present) that describe the
  relation between \p ph and \p g.
*/
int
ppl_Polyhedron_relation_with_Generator PPL_PROTO((ppl_const_Polyhedron_t ph,
						  ppl_const_Generator_t g));

/*! \brief
  Use \p ph to shrink a generic, interval-based bounding box.
  The bounding box is abstractly provided by means of the parameters.

  \param ph
  The polyhedron that is used to shrink the bounding box;

  \param complexity
  The code of the complexity class of the algorithm to be used.
  Must be one of PPL_COMPLEXITY_CLASS_POLYNOMIAL,
  PPL_COMPLEXITY_CLASS_SIMPLEX, or PPL_COMPLEXITY_CLASS_ANY;

  \param set_empty
  A pointer to a void function with no arguments that causes the bounding
  box to become empty, i.e., to represent the empty set;

  \param raise_lower_bound
  A pointer to a void function with arguments
  <CODE>(ppl_dimension_type k, int closed,
         ppl_const_Coefficient_t n, ppl_const_Coefficient_t d)</CODE>
  that intersects the interval corresponding to the <CODE>k</CODE>-th
  space dimension with \f$[n/d, +\infty)\f$ if <CODE>closed</CODE> is non-zero,
  with \f$(n/d, +\infty)\f$ if <CODE>closed</CODE> is zero.
  The fraction \f$n/d\f$ is in canonical form, that is, \f$n\f$
  and \f$d\f$ have no common factors and \f$d\f$ is positive, \f$0/1\f$
  being the unique representation for zero;

  \param lower_upper_bound
  a pointer to a void function with argument
  <CODE>(ppl_dimension_type k, int closed,
         ppl_const_Coefficient_t n, ppl_const_Coefficient_t d)</CODE>
  that intersects the interval corresponding to the <CODE>k</CODE>-th
  space dimension with \f$(-\infty, n/d]\f$ if <CODE>closed</CODE> is non-zero,
  with \f$(-\infty, n/d)\f$ if <CODE>closed</CODE> is zero.
  The fraction \f$n/d\f$ is in canonical form.
*/
int
ppl_Polyhedron_shrink_bounding_box
PPL_PROTO((ppl_const_Polyhedron_t ph,
	   unsigned int complexity,
	   void (*set_empty)(void),
	   void (*raise_lower_bound)(ppl_dimension_type k, int closed,
				     ppl_const_Coefficient_t n,
				     ppl_const_Coefficient_t d),
	   void (*lower_upper_bound)(ppl_dimension_type k, int closed,
				     ppl_const_Coefficient_t n,
				     ppl_const_Coefficient_t d)));

/*! \brief
  Returns a positive integer if \p ph is empty; returns 0 if \p ph is
  not empty.
*/
int
ppl_Polyhedron_is_empty PPL_PROTO((ppl_const_Polyhedron_t ph));

/*! \brief
  Returns a positive integer if \p ph is a universe polyhedron;
  returns 0 if it is not.
*/
int
ppl_Polyhedron_is_universe PPL_PROTO((ppl_const_Polyhedron_t ph));

/*! \brief
  Returns a positive integer if \p ph is bounded; returns 0 if \p ph is
  unbounded.
*/
int
ppl_Polyhedron_is_bounded PPL_PROTO((ppl_const_Polyhedron_t ph));

/*! \brief
  Returns a positive integer if \p le is bounded from above in \p ph;
  returns 0 otherwise.
*/
int
ppl_Polyhedron_bounds_from_above PPL_PROTO((ppl_const_Polyhedron_t ph,
					    ppl_const_Linear_Expression_t le));

/*! \brief
  Returns a positive integer if \p le is bounded from below in \p ph;
  returns 0 otherwise.
*/
int
ppl_Polyhedron_bounds_from_below PPL_PROTO((ppl_const_Polyhedron_t ph,
					    ppl_const_Linear_Expression_t le));

/*! \brief
  Returns a positive integer if \p ph is not empty
  and \p le is bounded from above in \p ph, in which case
  the supremum value and a point where \p le reaches it are computed.

  \param ph
  The polyhedron constraining \p le;

  \param le
  The linear expression to be maximized subject to \p ph;

  \param sup_n
  Will be assigned the numerator of the supremum value;

  \param sup_d
  Will be assigned the denominator of the supremum value;

  \param pmaximum
  Will store 1 in this location if the supremum is also the maximum,
  will store 0 otherwise;

  \param point
  Will be assigned the point or closure point where \p le reaches the
  extremum value.

  If \p ph is empty or \p le is not bounded from above,
  0 will be returned and \p sup_n, \p sup_d, \p *pmaximum and \p point
  will be left untouched.
*/
int
ppl_Polyhedron_maximize PPL_PROTO((ppl_const_Polyhedron_t ph,
				   ppl_const_Linear_Expression_t le,
				   ppl_Coefficient_t sup_n,
				   ppl_Coefficient_t sup_d,
				   int* pmaximum,
				   ppl_Generator_t point));

/*! \brief
  Returns a positive integer if  \p ph is not empty
  and \p le is bounded from below in \p ph, in which case
  the infimum value and a point where \p le reaches it are computed.

  \param ph
  The polyhedron constraining \p le;

  \param le
  The linear expression to be minimized subject to \p ph;

  \param inf_n
  Will be assigned the numerator of the infimum value;

  \param inf_d
  Will be assigned the denominator of the infimum value;

  \param pminimum
  Will store 1 in this location if the infimum is also the minimum,
  will store 0 otherwise;

  \param point
  Will be assigned the point or closure point where \p le reaches the
  extremum value.

  If \p ph is empty or \p le is not bounded from below,
  0 will be returned and \p sup_n, \p sup_d, \p *pmaximum and \p point
  will be left untouched.
*/
int
ppl_Polyhedron_minimize PPL_PROTO((ppl_const_Polyhedron_t ph,
				   ppl_const_Linear_Expression_t le,
				   ppl_Coefficient_t inf_n,
				   ppl_Coefficient_t inf_d,
				   int* pminimum,
				   ppl_Generator_t point));

/*! \brief
  Returns a positive integer if \p ph is topologically closed;
  returns 0 if \p ph is not topologically closed.
*/
int
ppl_Polyhedron_is_topologically_closed PPL_PROTO((ppl_const_Polyhedron_t ph));

/*! \brief
  Returns a positive integer if \p x contains or is equal to \p y;
  returns 0 if it does not.
*/
int
ppl_Polyhedron_contains_Polyhedron PPL_PROTO((ppl_const_Polyhedron_t x,
					      ppl_const_Polyhedron_t y));

/*! \brief
  Returns a positive integer if \p x strictly contains \p y; returns 0
  if it does not.
*/
int
ppl_Polyhedron_strictly_contains_Polyhedron
PPL_PROTO((ppl_const_Polyhedron_t x, ppl_const_Polyhedron_t y));

/*! \brief
  Returns a positive integer if \p x and \p y are disjoint; returns 0
  if they are not.
*/
int
ppl_Polyhedron_is_disjoint_from_Polyhedron
PPL_PROTO((ppl_const_Polyhedron_t x, ppl_const_Polyhedron_t y));

/*! \brief
  Returns a positive integer if \p x and \p y are the same polyhedron;
  returns 0 if they are different.

  Note that \p x and \p y may be topology- and/or dimension-incompatible
  polyhedra: in those cases, the value 0 is returned.
*/
int
ppl_Polyhedron_equals_Polyhedron PPL_PROTO((ppl_const_Polyhedron_t x,
					    ppl_const_Polyhedron_t y));

/*! \brief
  Returns a positive integer if \p ph is well formed, i.e., if it
  satisfies all its implementation invariants; returns 0 and perhaps
  makes some noise if \p ph is broken.  Useful for debugging purposes.
*/
int
ppl_Polyhedron_OK PPL_PROTO((ppl_const_Polyhedron_t ph));

/*! \brief
  Adds a copy of the constraint \p c to the system of constraints of
  \p ph.
*/
int
ppl_Polyhedron_add_constraint PPL_PROTO((ppl_Polyhedron_t ph,
					 ppl_const_Constraint_t c));

/*! \brief
  Adds a copy of the constraint \p c to the system of constraints of
  \p ph.  Returns a positive integer if the resulting polyhedron is
  non-empty; returns 0 if it is empty.  Upon successful return, \p ph
  is guaranteed to be minimized.
*/
int
ppl_Polyhedron_add_constraint_and_minimize
PPL_PROTO((ppl_Polyhedron_t ph, ppl_const_Constraint_t c));

/*! \brief
  Adds a copy of the generator \p g to the system of generators of
  \p ph.
*/
int
ppl_Polyhedron_add_generator PPL_PROTO((ppl_Polyhedron_t ph,
					ppl_const_Generator_t g));

/*! \brief
  Adds a copy of the generator \p g to the system of generators of
  \p ph.  Returns a positive integer if the resulting polyhedron is
  non-empty; returns 0 if it is empty.  Upon successful return, \p ph
  is guaranteed to be minimized.
*/
int
ppl_Polyhedron_add_generator_and_minimize PPL_PROTO((ppl_Polyhedron_t ph,
						     ppl_const_Generator_t g));

/*! \brief
  Adds a copy of the system of constraints \p cs to the system of
  constraints of \p ph.
*/
int
ppl_Polyhedron_add_constraints PPL_PROTO((ppl_Polyhedron_t ph,
					  ppl_const_Constraint_System_t cs));

/*! \brief
  Adds a copy of the system of constraints \p cs to the system of
  constraints of \p ph.  Returns a positive integer if the resulting
  polyhedron is non-empty; returns 0 if it is empty.  Upon successful
  return, \p ph is guaranteed to be minimized.
*/
int
ppl_Polyhedron_add_constraints_and_minimize
PPL_PROTO((ppl_Polyhedron_t ph, ppl_const_Constraint_System_t cs));

/*! \brief
  Adds a copy of the system of generators \p gs to the system of
  generators of \p ph.
*/
int
ppl_Polyhedron_add_generators PPL_PROTO((ppl_Polyhedron_t ph,
					 ppl_const_Generator_System_t gs));

/*! \brief
  Adds a copy of the system of generators \p gs to the system of
  generators of \p ph.  Returns a positive integer if the resulting
  polyhedron is non-empty; returns 0 if it is empty.  Upon successful
  return, \p ph is guaranteed to be minimized.
*/
int
ppl_Polyhedron_add_generators_and_minimize
PPL_PROTO((ppl_Polyhedron_t ph, ppl_const_Generator_System_t gs));

/*! \brief
  Adds the system of constraints \p cs to the system of constraints of
  \p ph.

  \warning
  This function modifies the constraint system referenced by \p cs:
  upon return, no assumption can be made on its value.
*/
int
ppl_Polyhedron_add_recycled_constraints
PPL_PROTO((ppl_Polyhedron_t ph, ppl_Constraint_System_t cs));

/*! \brief
  Adds the system of constraints \p cs to the system of constraints of
  \p ph.  Returns a positive integer if the resulting polyhedron is
  non-empty; returns 0 if it is empty.  Upon successful return, \p ph
  is guaranteed to be minimized.

  \warning
  This function modifies the constraint system referenced by \p cs:
  upon return, no assumption can be made on its value.
*/
int
ppl_Polyhedron_add_recycled_constraints_and_minimize
PPL_PROTO((ppl_Polyhedron_t ph, ppl_Constraint_System_t cs));

/*! \brief
  Adds the system of generators \p gs to the system of generators of
  \p ph.

  \warning
  This function modifies the generator system referenced by \p gs:
  upon return, no assumption can be made on its value.
*/
int
ppl_Polyhedron_add_recycled_generators PPL_PROTO((ppl_Polyhedron_t ph,
						  ppl_Generator_System_t gs));

/*! \brief
  Adds the system of generators \p gs to the system of generators of
  \p ph.  Returns a positive integer if the resulting polyhedron is
  non-empty; returns 0 if it is empty.  Upon successful return, \p ph
  is guaranteed to be minimized.

  \warning
  This function modifies the generator system referenced by \p gs:
  upon return, no assumption can be made on its value.
*/
int
ppl_Polyhedron_add_recycled_generators_and_minimize
PPL_PROTO((ppl_Polyhedron_t ph, ppl_Generator_System_t gs));

/*! \brief
  Intersects \p x with polyhedron \p y and assigns the result to \p x.
*/
int
ppl_Polyhedron_intersection_assign PPL_PROTO((ppl_Polyhedron_t x,
					      ppl_const_Polyhedron_t y));

/*! \brief
  Intersects \p x with polyhedron \p y and assigns the result to \p x.
  Returns a positive integer if the resulting polyhedron is non-empty;
  returns 0 if it is empty.  Upon successful return, \p x is also
  guaranteed to be minimized.
*/
int
ppl_Polyhedron_intersection_assign_and_minimize
PPL_PROTO((ppl_Polyhedron_t x, ppl_const_Polyhedron_t y));

/*! \brief
  Assigns to \p x the poly-hull of \p x and \p y.
*/
int
ppl_Polyhedron_poly_hull_assign PPL_PROTO((ppl_Polyhedron_t x,
					   ppl_const_Polyhedron_t y));

/*! \brief
  Assigns to \p x the poly-hull of \p x and \p y. Returns a positive
  integer if the resulting polyhedron is non-empty; returns 0 if it is
  empty. Upon successful return, \p x is also guaranteed to be minimized.
*/
int
ppl_Polyhedron_poly_hull_assign_and_minimize
PPL_PROTO((ppl_Polyhedron_t x, ppl_const_Polyhedron_t y));

/*! \brief
  Assigns to \p x the \ref Convex_Polyhedral_Difference "poly-difference"
  of \p x and \p y.
*/
int
ppl_Polyhedron_poly_difference_assign PPL_PROTO((ppl_Polyhedron_t x,
						 ppl_const_Polyhedron_t y));

/*! \brief
  Transforms the polyhedron \p ph, assigning an affine expression
  to the specified variable.

  \param ph
  The polyhedron that is transformed;

  \param var
  The variable to which the affine expression is assigned;

  \param le
  The numerator of the affine expression;

  \param d
  The denominator of the affine expression.
*/
int
ppl_Polyhedron_affine_image PPL_PROTO((ppl_Polyhedron_t ph,
				       ppl_dimension_type var,
				       ppl_const_Linear_Expression_t le,
				       ppl_const_Coefficient_t d));

/*! \brief
  Transforms the polyhedron \p ph, substituting an affine expression
  to the specified variable.

  \param ph
  The polyhedron that is transformed;

  \param var
  The variable to which the affine expression is substituted;

  \param le
  The numerator of the affine expression;

  \param d
  The denominator of the affine expression.
*/
int
ppl_Polyhedron_affine_preimage PPL_PROTO((ppl_Polyhedron_t ph,
					  ppl_dimension_type var,
					  ppl_const_Linear_Expression_t le,
					  ppl_const_Coefficient_t d));

/*! \brief
  Assigns to \p ph the image of \p ph with respect to the
  \ref Generalized_Affine_Relations "generalized affine transfer relation"
  \f$\frac{\mathrm{lb}}{\mathrm{d}}
       \leq \mathrm{var}'
         \leq \frac{\mathrm{ub}}{\mathrm{d}}\f$.

  \param ph
  The polyhedron that is transformed;

  \param var
  The variable bounded by the generalized affine transfer relation;

  \param lb
  The numerator of the lower bounding affine expression;

  \param ub
  The numerator of the upper bounding affine expression;

  \param d
  The (common) denominator of the lower and upper bounding affine expressions.
*/
int
ppl_Polyhedron_bounded_affine_image
PPL_PROTO((ppl_Polyhedron_t ph,
	   ppl_dimension_type var,
	   ppl_const_Linear_Expression_t lb,
	   ppl_const_Linear_Expression_t ub,
	   ppl_const_Coefficient_t d));

/*! \brief
  Assigns to \p ph the preimage of \p ph with respect to the
  \ref Generalized_Affine_Relations "generalized affine transfer relation"
  \f$\frac{\mathrm{lb}}{\mathrm{d}}
       \leq \mathrm{var}'
         \leq \frac{\mathrm{ub}}{\mathrm{d}}\f$.

  \param ph
  The polyhedron that is transformed;

  \param var
  The variable bounded by the generalized affine transfer relation;

  \param lb
  The numerator of the lower bounding affine expression;

  \param ub
  The numerator of the upper bounding affine expression;

  \param d
  The (common) denominator of the lower and upper bounding affine expressions.
*/
int
ppl_Polyhedron_bounded_affine_preimage
PPL_PROTO((ppl_Polyhedron_t ph,
	   ppl_dimension_type var,
	   ppl_const_Linear_Expression_t lb,
	   ppl_const_Linear_Expression_t ub,
	   ppl_const_Coefficient_t d));

/*! \brief
  Assigns to \p ph the image of \p ph with respect to the
  \ref Generalized_Affine_Relations "generalized affine transfer relation"
  \f$\mathrm{var}' \relsym \frac{\mathrm{le}}{\mathrm{d}}\f$,
  where \f$\mathord{\relsym}\f$ is the relation symbol encoded
  by \p relsym.

  \param ph
  The polyhedron that is transformed;

  \param var
  The left hand side variable of the generalized affine transfer relation;

  \param relsym
  The relation symbol;

  \param le
  The numerator of the right hand side affine expression;

  \param d
  The denominator of the right hand side affine expression.
*/
int
ppl_Polyhedron_generalized_affine_image
PPL_PROTO((ppl_Polyhedron_t ph,
	   ppl_dimension_type var,
	   enum ppl_enum_Constraint_Type relsym,
	   ppl_const_Linear_Expression_t le,
	   ppl_const_Coefficient_t d));

/*! \brief
  Assigns to \p ph the preimage of \p ph with respect to the
  \ref Generalized_Affine_Relations "generalized affine transfer relation"
  \f$\mathrm{var}' \relsym \frac{\mathrm{le}}{\mathrm{d}}\f$,
  where \f$\mathord{\relsym}\f$ is the relation symbol encoded
  by \p relsym.

  \param ph
  The polyhedron that is transformed;

  \param var
  The left hand side variable of the generalized affine transfer relation;

  \param relsym
  The relation symbol;

  \param le
  The numerator of the right hand side affine expression;

  \param d
  The denominator of the right hand side affine expression.
*/
int
ppl_Polyhedron_generalized_affine_preimage
PPL_PROTO((ppl_Polyhedron_t ph,
	   ppl_dimension_type var,
	   enum ppl_enum_Constraint_Type relsym,
	   ppl_const_Linear_Expression_t le,
	   ppl_const_Coefficient_t d));

/*! \brief
  Assigns to \p ph the image of \p ph with respect to the
  \ref Generalized_Affine_Relations "generalized affine transfer relation"
  \f$\mathrm{lhs}' \relsym \mathrm{rhs}\f$, where
  \f$\mathord{\relsym}\f$ is the relation symbol encoded by \p relsym.

  \param ph
  The polyhedron that is transformed;

  \param lhs
  The left hand side affine expression;

  \param relsym
  The relation symbol;

  \param rhs
  The right hand side affine expression.
*/
int
ppl_Polyhedron_generalized_affine_image_lhs_rhs
PPL_PROTO((ppl_Polyhedron_t ph,
	   ppl_const_Linear_Expression_t lhs,
	   enum ppl_enum_Constraint_Type relsym,
	   ppl_const_Linear_Expression_t rhs));

/*! \brief
  Assigns to \p ph the preimage of \p ph with respect to the
  \ref Generalized_Affine_Relations "generalized affine transfer relation"
  \f$\mathrm{lhs}' \relsym \mathrm{rhs}\f$, where
  \f$\mathord{\relsym}\f$ is the relation symbol encoded by \p relsym.

  \param ph
  The polyhedron that is transformed;

  \param lhs
  The left hand side affine expression;

  \param relsym
  The relation symbol;

  \param rhs
  The right hand side affine expression.
*/
int
ppl_Polyhedron_generalized_affine_preimage_lhs_rhs
PPL_PROTO((ppl_Polyhedron_t ph,
	   ppl_const_Linear_Expression_t lhs,
	   enum ppl_enum_Constraint_Type relsym,
	   ppl_const_Linear_Expression_t rhs));

/*! \brief
  Assigns to \p x the \ref Time_Elapse_Operator "time-elapse" between
  the polyhedra \p x and \p y.
*/
int
ppl_Polyhedron_time_elapse_assign PPL_PROTO((ppl_Polyhedron_t x,
					     ppl_const_Polyhedron_t y));

/*! \brief
  If the polyhedron \p y is contained in (or equal to) the polyhedron
  \p x, assigns to \p x the \ref BHRZ03_widening "BHRZ03-widening" of
  \p x and \p y.  If \p tp is not the null pointer, the
  \ref Widening_with_Tokens "widening with tokens" delay technique
  is applied with <CODE>*tp</CODE> available tokens.
*/
int
ppl_Polyhedron_BHRZ03_widening_assign_with_tokens
PPL_PROTO((ppl_Polyhedron_t x,
	   ppl_const_Polyhedron_t y,
	   unsigned* tp));

/*! \brief
  If the polyhedron \p y is contained in (or equal to) the polyhedron
  \p x, assigns to \p x the \ref BHRZ03_widening "BHRZ03-widening" of
  \p x and \p y.
*/
int
ppl_Polyhedron_BHRZ03_widening_assign PPL_PROTO((ppl_Polyhedron_t x,
						 ppl_const_Polyhedron_t y));

/*! \brief
  If the polyhedron \p y is contained in (or equal to) the polyhedron
  \p x, assigns to \p x the \ref BHRZ03_widening "BHRZ03-widening" of
  \p x and \p y intersected with the constraints in \p cs that are
  satisfied by all the points of \p x.  If \p tp is not the null pointer,
  the \ref Widening_with_Tokens "widening with tokens" delay technique
  is applied with <CODE>*tp</CODE> available tokens.
*/
int
ppl_Polyhedron_limited_BHRZ03_extrapolation_assign_with_tokens
PPL_PROTO((ppl_Polyhedron_t x,
	   ppl_const_Polyhedron_t y,
	   ppl_const_Constraint_System_t cs,
	   unsigned* tp));

/*! \brief
  If the polyhedron \p y is contained in (or equal to) the polyhedron
  \p x, assigns to \p x the \ref BHRZ03_widening "BHRZ03-widening" of
  \p x and \p y intersected with the constraints in \p cs that are
  satisfied by all the points of \p x.
*/
int
ppl_Polyhedron_limited_BHRZ03_extrapolation_assign
PPL_PROTO((ppl_Polyhedron_t x,
	   ppl_const_Polyhedron_t y,
	   ppl_const_Constraint_System_t cs));

/*! \brief
  If the polyhedron \p y is contained in (or equal to) the polyhedron
  \p x, assigns to \p x the \ref BHRZ03_widening "BHRZ03-widening" of
  \p x and \p y intersected with the constraints in \p cs that are
  satisfied by all the points of \p x, further intersected with all
  the constraints of the form \f$\pm v \leq r\f$ and \f$\pm v < r\f$,
  with \f$r \in \Qset\f$, that are satisfied by all the points of \p
  x. If \p tp is not the null pointer,
  the \ref Widening_with_Tokens "widening with tokens" delay technique
  is applied with <CODE>*tp</CODE> available tokens.
*/
int
ppl_Polyhedron_bounded_BHRZ03_extrapolation_assign_with_tokens
PPL_PROTO((ppl_Polyhedron_t x,
	   ppl_const_Polyhedron_t y,
	   ppl_const_Constraint_System_t cs,
	   unsigned* tp));

/*! \brief
  If the polyhedron \p y is contained in (or equal to) the polyhedron
  \p x, assigns to \p x the \ref BHRZ03_widening "BHRZ03-widening" of
  \p x and \p y intersected with the constraints in \p cs that are
  satisfied by all the points of \p x, further intersected with all
  the constraints of the form \f$\pm v \leq r\f$ and \f$\pm v < r\f$,
  with \f$r \in \Qset\f$, that are satisfied by all the points of \p x.
*/
int
ppl_Polyhedron_bounded_BHRZ03_extrapolation_assign
PPL_PROTO((ppl_Polyhedron_t x,
	   ppl_const_Polyhedron_t y,
	   ppl_const_Constraint_System_t cs));

/*! \brief
  If the polyhedron \p y is contained in (or equal to) the polyhedron
  \p x, assigns to \p x the \ref H79_widening "H79-widening" of \p x
  and \p y.  If \p tp is not the null pointer, the
  \ref Widening_with_Tokens "widening with tokens" delay technique is
  applied with <CODE>*tp</CODE> available tokens.
*/
int
ppl_Polyhedron_H79_widening_assign_with_tokens
PPL_PROTO((ppl_Polyhedron_t x,
	   ppl_const_Polyhedron_t y,
	   unsigned* tp));

/*! \brief
  If the polyhedron \p y is contained in (or equal to) the polyhedron
  \p x, assigns to \p x the \ref H79_widening "H79-widening" of \p x
  and \p y.
*/
int
ppl_Polyhedron_H79_widening_assign PPL_PROTO((ppl_Polyhedron_t x,
					      ppl_const_Polyhedron_t y));

/*! \brief
  If the polyhedron \p y is contained in (or equal to) the polyhedron
  \p x, assigns to \p x the \ref H79_widening "H79-widening" of \p x
  and \p y intersected with the constraints in \p cs that are
  satisfied by all the points of \p x. If \p tp is not the null
  pointer, the \ref Widening_with_Tokens "widening with tokens" delay
  technique is applied with <CODE>*tp</CODE> available tokens.
*/
int
ppl_Polyhedron_limited_H79_extrapolation_assign_with_tokens
PPL_PROTO((ppl_Polyhedron_t x,
	   ppl_const_Polyhedron_t y,
	   ppl_const_Constraint_System_t cs,
	   unsigned* tp));

/*! \brief
  If the polyhedron \p y is contained in (or equal to) the polyhedron
  \p x, assigns to \p x the \ref H79_widening "H79-widening" of \p x
  and \p y intersected with the constraints in \p cs that are
  satisfied by all the points of \p x.
*/
int
ppl_Polyhedron_limited_H79_extrapolation_assign
PPL_PROTO((ppl_Polyhedron_t x,
	   ppl_const_Polyhedron_t y,
	   ppl_const_Constraint_System_t cs));

/*! \brief
  If the polyhedron \p y is contained in (or equal to) the polyhedron
  \p x, assigns to \p x the \ref H79_widening "H79-widening" of \p x
  and \p y intersected with the constraints in \p cs that are
  satisfied by all the points of \p x, further intersected with all
  the constraints of the form \f$\pm v \leq r\f$ and \f$\pm v < r\f$,
  with \f$r \in \Qset\f$, that are satisfied by all the points of \p x.
  If \p tp is not the null pointer,
  the \ref Widening_with_Tokens "widening with tokens" delay technique
  is applied with <CODE>*tp</CODE> available tokens.
*/
int
ppl_Polyhedron_bounded_H79_extrapolation_assign_with_tokens
PPL_PROTO((ppl_Polyhedron_t x,
	   ppl_const_Polyhedron_t y,
	   ppl_const_Constraint_System_t cs,
	   unsigned* tp));

/*! \brief
  If the polyhedron \p y is contained in (or equal to) the polyhedron
  \p x, assigns to \p x the \ref H79_widening "H79-widening" of \p x
  and \p y intersected with the constraints in \p cs that are
  satisfied by all the points of \p x, further intersected with all
  the constraints of the form \f$\pm v \leq r\f$ and \f$\pm v < r\f$,
  with \f$r \in \Qset\f$, that are satisfied by all the points of \p
  x.
*/
int
ppl_Polyhedron_bounded_H79_extrapolation_assign
PPL_PROTO((ppl_Polyhedron_t x,
	   ppl_const_Polyhedron_t y,
	   ppl_const_Constraint_System_t cs));

/*! \brief
  Assigns to \p ph its topological closure.
*/
int
ppl_Polyhedron_topological_closure_assign PPL_PROTO((ppl_Polyhedron_t ph));

/*! \brief
  Adds \p d new dimensions to the space enclosing the polyhedron \p ph
  and to \p ph itself.
*/
int
ppl_Polyhedron_add_space_dimensions_and_embed
PPL_PROTO((ppl_Polyhedron_t ph, ppl_dimension_type d));

/*! \brief
  Adds \p d new dimensions to the space enclosing the polyhedron \p ph.
*/
int
ppl_Polyhedron_add_space_dimensions_and_project
PPL_PROTO((ppl_Polyhedron_t ph, ppl_dimension_type d));

/*! \brief
  Seeing a polyhedron as a set of tuples (its points), assigns
  to \p x all the tuples that can be obtained by concatenating,
  in the order given, a tuple of \p x with a tuple of \p y.
*/
int
ppl_Polyhedron_concatenate_assign PPL_PROTO((ppl_Polyhedron_t x,
					     ppl_const_Polyhedron_t y));

/*! \brief
  Removes from the vector space enclosing \p ph the space dimensions that
  are specified in first \p n positions of the array \p ds.  The presence
  of duplicates in \p ds is a waste but an innocuous one.
*/
int
ppl_Polyhedron_remove_space_dimensions PPL_PROTO((ppl_Polyhedron_t ph,
						  ppl_dimension_type ds[],
						  size_t n));

/*! \brief
  Removes the higher dimensions from the vector space enclosing \p ph
  so that, upon successful return, the new space dimension is \p d.
*/
int
ppl_Polyhedron_remove_higher_space_dimensions
PPL_PROTO((ppl_Polyhedron_t ph, ppl_dimension_type d));

/*! \brief
  Remaps the dimensions of the vector space according to a
  \ref Mapping_the_Dimensions_of_the_Vector_Space "partial function".
  This function is specified by means of the \p maps array,
  which has \p n entries.

  The partial function is defined on dimension <CODE>i</CODE>
  if <CODE>i < n</CODE> and <CODE>maps[i] != ppl_not_a_dimension</CODE>;
  otherwise it is undefined on dimension <CODE>i</CODE>.
  If the function is defined on dimension <CODE>i</CODE>, then dimension
  <CODE>i</CODE> is mapped onto dimension <CODE>maps[i]</CODE>.

  The result is undefined if \p maps 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".
*/
int
ppl_Polyhedron_map_space_dimensions PPL_PROTO((ppl_Polyhedron_t ph,
					       ppl_dimension_type maps[],
					       size_t n));

/*! \brief
  \ref expand_space_dimension "Expands" the \f$d\f$-th dimension of
  the vector space enclosing \p ph to \p m new space dimensions.
*/
int
ppl_Polyhedron_expand_space_dimension PPL_PROTO((ppl_Polyhedron_t ph,
						 ppl_dimension_type d,
						 ppl_dimension_type m));

/*! \brief
  Modifies \p ph by \ref fold_space_dimensions "folding" the
  space dimensions contained in the first \p n positions of the array \p ds
  into dimension \p d.  The presence of duplicates in \p ds is a waste
  but an innocuous one.
*/
int
ppl_Polyhedron_fold_space_dimensions PPL_PROTO((ppl_Polyhedron_t ph,
						ppl_dimension_type ds[],
						size_t n,
						ppl_dimension_type d));

/*@}*/ /* Functions Related to Polyhedra */


/*! \name Functions Related to LP Problems */
/*@{*/

/*! \brief
  Builds a trivial LP problem and writes a handle to it at address \p plp.
*/
int
ppl_new_LP_Problem_trivial PPL_PROTO((ppl_LP_Problem_t* plp));

/*! \brief
  Builds an LP problem having feasible region \p cs, objective function
  \p le and optimization mode \p m; writes a handle to it at address \p plp.
*/
int
ppl_new_LP_Problem PPL_PROTO((ppl_LP_Problem_t* plp,
			      ppl_const_Constraint_System_t cs,
			      ppl_const_Linear_Expression_t le,
			      int m));

/*! \brief
  Builds an LP problem that is a copy of \p lp; writes a handle
  for the newly created system at address \p plp.
*/
int
ppl_new_LP_Problem_from_LP_Problem
PPL_PROTO((ppl_LP_Problem_t* plp, ppl_const_LP_Problem_t lp));

/*! \brief
  Invalidates the handle \p lp: this makes sure the corresponding
  resources will eventually be released.
*/
int
ppl_delete_LP_Problem PPL_PROTO((ppl_const_LP_Problem_t lp));

/*! \brief
  Assigns a copy of the LP problem \p src to \p dst.
*/
int
ppl_assign_LP_Problem_from_LP_Problem
PPL_PROTO((ppl_LP_Problem_t dst, ppl_const_LP_Problem_t src));

/*! \brief
  Writes to \p m the dimension of the vector space enclosing \p lp.
*/
int
ppl_LP_Problem_space_dimension
PPL_PROTO((ppl_const_LP_Problem_t lp, ppl_dimension_type* m));

/*! \brief
  Writes a const handle to the constraint system defining the
  feasible region of the LP problem \p lp at address \p pcs.
*/
int
ppl_LP_Problem_constraints PPL_PROTO((ppl_const_LP_Problem_t lp,
				      ppl_const_Constraint_System_t* pcs));

/*! \brief
  Writes a const handle to the linear expression defining the
  objective function of the LP problem \p lp at address \p ple.
*/
int
ppl_LP_Problem_objective_function
PPL_PROTO((ppl_const_LP_Problem_t lp, ppl_const_Linear_Expression_t* ple));

/*! \brief
  Returns the optimization mode of the LP problem \p lp.
*/
int
ppl_LP_Problem_optimization_mode PPL_PROTO((ppl_const_LP_Problem_t lp));

/*! \brief
  Resets the LP problem to be a trivial problem of space dimension 0.
*/
int
ppl_LP_Problem_clear PPL_PROTO((ppl_LP_Problem_t lp));

/*! \brief
  Modifies the feasible region of the LP problem \p lp by adding a copy
  of the constraint \p c; the space dimension is increased, if necessary.
*/
int
ppl_LP_Problem_add_constraint PPL_PROTO((ppl_LP_Problem_t lp,
					 ppl_const_Constraint_t c));

/*! \brief
  Modifies the feasible region of the LP problem \p lp by adding a copy
  of the constraints in \p cs; the space dimension is increased, if necessary.
*/
int
ppl_LP_Problem_add_constraints PPL_PROTO((ppl_LP_Problem_t lp,
					  ppl_const_Constraint_System_t cs));

/*! \brief
  Sets the objective function of the LP problem \p lp to a copy of \p le.
*/
int
ppl_LP_Problem_set_objective_function
PPL_PROTO((ppl_LP_Problem_t lp, ppl_const_Linear_Expression_t le));

/*! \brief
  Sets the optimization mode of the LP problem \p lp to \p mode.
*/
int
ppl_LP_Problem_set_optimization_mode PPL_PROTO((ppl_LP_Problem_t lp,
						int mode));

/*! \brief
  Returns a positive integer if \p lp is satisfiable; returns 0 otherwise.
*/
int
ppl_LP_Problem_is_satisfiable PPL_PROTO((ppl_const_LP_Problem_t lp));

/*! \brief
  Solves the LP problem \p lp, returning an exit status.

  \return
  <CODE>PPL_LP_PROBLEM_STATUS_UNFEASIBLE</CODE> if the LP problem
  is not satisfiable;
  <CODE>PPL_LP_PROBLEM_STATUS_UNBOUNDED</CODE> if the LP problem
  is satisfiable but there is no finite bound to the value of
  the objective function;
  <CODE>PPL_LP_PROBLEM_STATUS_OPTIMIZED</CODE> if the LP problem
  admits an optimal solution.
*/
int
ppl_LP_Problem_solve PPL_PROTO((ppl_const_LP_Problem_t lp));

/*! \brief
  Evaluates the objective function of \p lp on point \p g.

  \param lp
  The LP problem defining the objective function;

  \param g
  The generator on which the objective function will be evaluated;

  \param num
  Will be assigned the numerator of the objective function value;

  \param den
  Will be assigned the denominator of the objective function value;
*/
int
ppl_LP_Problem_evaluate_objective_function
PPL_PROTO((ppl_const_LP_Problem_t lp, ppl_const_Generator_t g,
	   ppl_Coefficient_t num, ppl_Coefficient_t den));

/*! \brief
  Writes a const handle to a feasible point for the LP problem \p lp
  at address \p pg.
*/
int
ppl_LP_Problem_feasible_point PPL_PROTO((ppl_const_LP_Problem_t lp,
					 ppl_const_Generator_t* pg));

/*! \brief
  Writes a const handle to an optimizing point for the LP problem \p lp
  at address \p pg.
*/
int
ppl_LP_Problem_optimizing_point PPL_PROTO((ppl_const_LP_Problem_t lp,
					   ppl_const_Generator_t* pg));

/*! \brief
  Returns the optimal value for \p lp.

  \param lp
  The LP problem;

  \param num
  Will be assigned the numerator of the optimal value;

  \param den
  Will be assigned the denominator of the optimal value.
*/
int
ppl_LP_Problem_optimal_value
PPL_PROTO((ppl_const_LP_Problem_t lp,
	   ppl_Coefficient_t num, ppl_Coefficient_t den));

/*! \brief
  Returns a positive integer if \p lp is well formed, i.e., if it
  satisfies all its implementation invariants; returns 0 and perhaps
  makes some noise if \p lp is broken.  Useful for debugging purposes.
*/
int
ppl_LP_Problem_OK PPL_PROTO((ppl_const_LP_Problem_t lp));

/*@}*/ /* Functions Related to LP Problems */


/*! \name Simple I/O Functions */
/*@{*/

/*! \brief Pretty-prints \p var to <CODE>stdout</CODE>. */
int
ppl_io_print_variable PPL_PROTO((ppl_dimension_type var));

/*! \brief Pretty-prints \p var to the given output \p stream. */
int
ppl_io_fprint_variable PPL_PROTO((FILE* stream, ppl_dimension_type var));

#undef PPL_DECLARE_PRINT_FUNCTIONS

#define PPL_DECLARE_PRINT_FUNCTIONS(Type) \
/*! \brief Prints \p x to <CODE>stdout</CODE>. */ \
int \
ppl_io_print_ ## Type PPL_PROTO((ppl_const_ ## Type ## _t x)); \
 \
/*! \brief Prints \p x to the given output \p stream. */ \
int \
ppl_io_fprint_ ## Type PPL_PROTO((FILE* stream, ppl_const_ ## Type ## _t x));

PPL_DECLARE_PRINT_FUNCTIONS(Coefficient)

PPL_DECLARE_PRINT_FUNCTIONS(Linear_Expression)

PPL_DECLARE_PRINT_FUNCTIONS(Constraint)

PPL_DECLARE_PRINT_FUNCTIONS(Constraint_System)

PPL_DECLARE_PRINT_FUNCTIONS(Generator)

PPL_DECLARE_PRINT_FUNCTIONS(Generator_System)

PPL_DECLARE_PRINT_FUNCTIONS(Polyhedron)

#undef PPL_DECLARE_PRINT_FUNCTIONS

/*! \brief
  The type of output functions used for printing variables.

  An output function for variables must write a textual representation
  for \p var to a character buffer, null-terminate it, and return a
  pointer to the beginning of the buffer.  In case the operation fails,
  0 should be returned and perhaps <CODE>errno</CODE> should be set
  in a meaningful way.  The library does nothing with the buffer, besides
  printing its contents.
*/
typedef const char*
ppl_io_variable_output_function_type(ppl_dimension_type var);

/*! \brief
  Sets the output function to be used for printing variables to \p p.
*/
int
ppl_io_set_variable_output_function(ppl_io_variable_output_function_type* p);

/*! \brief
  Writes a pointer to the current variable output function to \p pp.
*/
int
ppl_io_get_variable_output_function(ppl_io_variable_output_function_type** pp);

/*@}*/ /* Simple I/O Functions */

#ifdef __cplusplus
} /* extern "C" */
#endif

#undef PPL_PROTO

/*@}*/ /* \defgroup PPL_C_interface */

#endif /* !defined(PPL_ppl_c_h) */
