/* Determinate class declaration.
   Copyright (C) 2001-2004 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., 59 Temple Place - Suite 330, 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_Determinate_defs_hh
#define PPL_Determinate_defs_hh

#include "Determinate.types.hh"
#include "ConSys.types.hh"
#include "Variable.defs.hh"
#include "globals.hh"
#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
  \exception std::invalid_argument
  Thrown if \p x and \p y are topology-incompatible or
  dimension-incompatible.
*/
template <typename PH>
bool operator==(const Determinate<PH>& x, const Determinate<PH>& y);

//! \brief
//! Returns <CODE>true</CODE> if and only if
//! \p x and \p y are different domain elements.
/*!
  \relates Determinate
  \exception std::invalid_argument
  Thrown if \p x and \p y are topology-incompatible or
  dimension-incompatible.
*/
template <typename PH>
bool operator!=(const Determinate<PH>& x, const Determinate<PH>& y);

namespace IO_Operators {

//! Output operator.
/*! \relates Parma_Polyhedra_Library::Determinate */
template <typename PH>
std::ostream&
operator<<(std::ostream&, const Determinate<PH>&);

} // namespace IO_Operators

} // namespace Parma_Polyhedra_Library

//! Wraps a PPL class into a determinate constraint system interface.
template <typename PH>
class Parma_Polyhedra_Library::Determinate {
public:

  //! \name Constructors and Destructor
  //@{

  //! \brief
  //! Builds either the top or the bottom of the determinate constraint
  //! system defined on the vector space having \p num_dimensions
  //! dimensions.
  /*!
    The top element, corresponding to the whole vector space,
    is built if \p universe is \c true; otherwise the bottom element,
    corresponding to the emptyset, is built. By default,
    the top of a zero-dimension vector space is built.
  */
  explicit
  Determinate(dimension_type num_dimensions = 0, bool universe = true);

  //! \brief
  //! Injection operator: builds the determinate constraint system element
  //! corresponding to the base-level element \p p.
  Determinate(const PH& p);

  //! \brief
  //! Injection operator: builds the determinate constraint system element
  //! corresponding to the base-level element represented by \p cs.
  Determinate(const ConSys& cs);

  //! Copy constructor.
  Determinate(const Determinate& y);

  //! Destructor.
  ~Determinate();

  //@} // Constructors and Destructor

  //! \name Member Functions that Do Not Modify the Domain Element
  //@{

  //! Returns the dimension of the vector space enclosing \p *this.
  dimension_type space_dimension() const;

  //! Returns the system of constraints.
  const ConSys& constraints() const;

  //! Returns the system of constraints, with no redundant constraint.
  const ConSys& minimized_constraints() const;

  //! Returns a const reference to the embedded element.
  const PH& element() const;

  //! Returns a reference to the embedded element.
  PH& element();

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  //! \brief
  //! On return from this method, the representation of \p *this
  //! is not shared by different Determinate objects.
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  void mutate();

  //! \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 (i.e., the emptyset).
  bool is_bottom() const;

  //! \brief
  //! Returns <CODE>true</CODE> if and only if \p *this entails \p y
  //! (i.e., \p *this is contained in \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;

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

  //@} // Member Functions that Do Not Modify the Domain Element


  Determinate& operator <<= (dimension_type n);
  Determinate& hide_assign(dimension_type n);

  friend bool
  operator==<PH>(const Determinate<PH>& x, const Determinate<PH>& y);
  friend bool
  operator!=<PH>(const Determinate<PH>& x, const Determinate<PH>& y);

#if 0
  friend Determinate operator +<>(const Determinate& x,
				  const Determinate& y);
  friend Determinate operator *<>(const Determinate& x,
				  const Determinate& y);
#endif

  //! \name Space-Dimension Preserving Member Functions that May Modify the Domain Element
  //@{

  //! \brief
  //! Assigns to \p *this the upper bound of \p *this and \p y.
  void upper_bound_assign(const Determinate& y);

  //! Assigns to \p *this the meet of \p *this and \p y.
  void meet_assign(const Determinate& y);

  //! \brief
  //! Assigns to \p *this the meet of \p *this and the element
  //! represented by 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
  //! Assigns to \p *this the meet of \p *this and the element
  //! represented by the constraints in \p cs.
  /*!
    \param cs
    The constraints to intersect with.  This parameter is not declared
    <CODE>const</CODE> because it can be modified.

    \exception std::invalid_argument
    Thrown if \p *this and \p cs are topology-incompatible or
    dimension-incompatible.
  */
  void add_constraints(ConSys& cs);

  //@} // Space-Dimension Preserving Member Functions that May Modify [...]

  //! \name Member Functions that May Modify the Dimension of the Vector Space
  //@{

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

  //! Swaps \p *this with \p y.
  void swap(Determinate& y);

  //! \brief
  //! Adds \p m new dimensions and embeds the old domain element
  //! in the new vector space.
  void add_dimensions_and_embed(dimension_type m);

  //! \brief
  //! Adds \p m new dimensions to the domain element
  //! and does not embed it in the new vector space.
  void add_dimensions_and_project(dimension_type m);

  //! \brief
  //! Assigns to \p *this the \ref concatenate "concatenation"
  //! of \p *this and \p y, taken in this order.
  void concatenate_assign(const Determinate& y);

  //! \brief
  //! 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_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_dimensions is greater than the space dimension
    of \p *this.
  */
  void remove_higher_dimensions(dimension_type new_dimension);

  //! \brief
  //! Remaps the dimensions of the vector space according to
  //! a partial function.
  /*!
    See Polyhedron::map_dimensions.
  */
  template <typename PartialFunction>
  void map_dimensions(const PartialFunction& pfunc);

  //@} // Member Functions that May Modify the Dimension of the Vector Space

private:
  //! The possibly shared representation of a Determinate object.
  /*!
    By adopting the <EM>copy-on-write</EM> technique, a single
    representation of the base-level object may be shared by more than
    one object of the class Determinate.
  */
  class Rep {
  private:
    //! \brief
    //! Count the number of references:
    //! -   0: leaked, \p ph is non-const;
    //! -   1: one reference, \p ph is non-const;
    //! - > 1: more than one reference, \p ph is const.
    mutable unsigned long references;

    //! Private and unimplemented: assignment not allowed.
    Rep& operator=(const Rep& y);

    //! Private and unimplemented: copies not allowed.
    Rep(const Rep& y);

    //! Private and unimplemented: default construction not allowed.
    Rep();

  public:
    //! A possibly shared base-level domain element.
    PH ph;

    //! \brief
    //! Builds a new representation by creating a domain element
    //! of the specified kind, in the specified vector space.
    Rep(dimension_type num_dimensions, Polyhedron::Degenerate_Kind kind);

    //! Builds a new representation by copying base-level element \p p.
    Rep(const PH& p);

    //! Builds a new representation by copying the constraints in \p cs.
    Rep(const ConSys& cs);

    //! 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
  //! A pointer to the possibly shared representation of
  //! the base-level domain element.
  Rep* prep;
};


namespace std {

//! Specializes <CODE>std::swap</CODE>.
/*! \relates Parma_Polyhedra_Library::Determinate */
template <typename PH>
void swap(Parma_Polyhedra_Library::Determinate<PH>& x,
	  Parma_Polyhedra_Library::Determinate<PH>& y);

} // namespace std

#include "Determinate.inlines.hh"

#endif // !defined(PPL_Determinate_defs_hh)


syntax highlighted by Code2HTML, v. 0.9.1