(***********************************************************************)
(*                                                                     *)
(*                           FaCiLe                                    *)
(*                 A Functional Constraint Library                     *)
(*                                                                     *)
(*            Nicolas Barnier, Pascal Brisset, LOG, CENA               *)
(*                                                                     *)
(* Copyright 2004 CENA. All rights reserved. This file is distributed  *)
(* under the terms of the GNU Lesser General Public License.           *)
(***********************************************************************)
(* $Id: fcl_domain.mli,v 1.48 2004/07/23 16:37:34 barnier Exp $ *)

(** Domain Operations *)

(** This module provides functions to create
   and handle domains, which are useful to build variables and perform
   propagation (i.e. domain filtering). *)
   
type elt = int
(** Type of element of domains (for generic interface,
   {% see~\ref{moduletype:Var.ATTR}%}). *)

type t
(** Type of finite domains of integers (functional: no in-place
   modifications, domains can be shared). Standard equality and
   comparison can be used on domains. *)

(** {% \subsection{Building New Domains} %} *)

val empty : t
(** The empty domain. *)
val create : elt list -> t
(** [create l] builds a new domain containing the values of [l]. Removes
   duplicates and sorts values. Returns [empty] if [l] is
   empty. *)
val unsafe_create : elt list -> t
(** [unsafe_create l] builds a new domain containing the values of [l]. [l] must
be sorted and must not contain duplicate values, otherwise the behaviour is
unspecified. Returns [empty] if [l] is empty. It is a more efficient variant
of [create]. *)
val interval : elt -> elt -> t
  (** [interval inf sup] returns the domain of all integers in the closed
     interval [[inf..sup]]. Raise [Invalid_argument] if [inf > sup]. *)
val int : t
  (** The largest representable domain. Handy to create variables for which
     bounds cannot be previously known. It is actually much smaller
     than [interval min_int max_int] (which really is the biggest one) to
     try to prevent overflows while computing bounds of expressions
     involving such variables. *)
val boolean : t
  (** The domain containing [0] and [1]. *)

(** {% \subsection{Access} %} *)

val is_empty : t -> bool
(** [is_empty d] tests whether the domain [d] is empty or not. *)
val size : t -> elt
(** [size d] returns the number of integers in [d]. *)
val min : t -> elt
val max : t -> elt
(** [min d] (resp. [max d]) returns the lower (resp. upper) bound of [d].
   If [d] is empty, the behaviour is unspecified (incorrect return value
   or exception raised). *)
val min_max : t -> elt * elt
(** [min_max d] returns both the lower and upper bound of [d]. If [d] is empty,
   the behaviour is unspecified (incorrect return value or exception
   raised). *)
val iter : (elt -> unit) -> t -> unit
  (** [iter f d] successively applies function [f] to all element of [d] in
  increasing order. *)
val interval_iter : (elt -> elt -> unit) -> t -> unit
  (** [interval_iter f d] successively applies function [f] to the bounds
     of all the disjoint intervals of [d] in increasing order. E.g. a
     suitable function [f] to print a domain can be defined as
     [fun mini maxi -> Printf.printf "%d..%d " mini maxi]. *)
val mem : elt -> t -> bool
val member : elt -> t -> bool
(** [member n d] tests if [n] belongs to [d]. *)
val values : t -> elt list
  (** [value d] returns the list of values of the domain [d] *)
val fprint_elt : out_channel -> elt -> unit
val fprint : out_channel -> t -> unit
(** Pretty printing of elements and domains. *)
val sprint : t -> string
(** [sprint d] returns a string representation of [d]. *)
val included : t -> t -> bool
  (** [included d1 d2] tests whether domain [d1] is included in domain [d2]. *)
val smallest_geq : t -> elt -> elt
val greatest_leq : t -> elt -> elt
  (** [smallest_geq dom val] (resp. [greatest_leq dom val]) returns the
     smallest (resp. greatest) value in [dom] greater (resp. smaller) than
     or equal to [val]. Raises [Not_found] if [max dom < val] (resp.
     [min dom > val]). *)
val largest_hole_around : t -> elt -> elt * elt
  (** [largest_hole_around dom val] returns the largest hole (interval)
      in [dom] centred around [val]. Returns [(val, val)] if [val]
      belongs to [dom] and raises [Not_found] if [val] is outside
      [dom] bounds. Equivalent to
      [(greatest_leq dom val, smallest_geq dom val)] but faster. *)
val choose : (elt -> elt -> bool) -> t -> elt
  (** [choose ord d] returns the mininum value of [d] for order [ord].
     Raises [Not_found] if [d] is empty. *)

(** {% \subsection{Operations} %} *)

val add : elt -> t -> t
(** [add n d] returns [d] {% $\cup$%} [{n}]. *)
val remove : elt -> t -> t
(** [remove n d] returns [d] {% $\setminus$ %} [{n}]. Returns [d] if [n]
    is not in [d]. *)
val remove_up : elt -> t -> t
val remove_low : elt -> t -> t
  (** [remove_up n d] (resp. [remove_low n d]) returns
      [d] {% $\setminus$ %} [[n+1..max_int]] (resp.
      [d] {% $\setminus$ %} [[min_int..n-1]]), i.e. removes values
     stricly greater (resp. less) than [n]. *)
val remove_low_up : elt -> elt -> t -> t
(** [remove_low_up low up d] is a shortcut for
   [remove_up up (remove_low low d)]. *)
val remove_closed_inter : elt -> elt -> t -> t
  (** [remove_closed_inter inf sup d] returns
      [d] {% $\setminus$ %} [[inf..sup]], i.e. removes
     values greater than or equal to [inf] and less or equal to [sup] in [d].
     Returns [d] if [inf > sup]. *)
val remove_min : t -> t
val remove_max : t -> t
(** [remove_min d] (resp. [remove_max d]) returns [d] without its lower
   (resp. upper) bound. Raises [Invalid_argument] if [d] is empty. *)
val intersection : t -> t -> t
val union : t -> t -> t
(** Intersection (resp. union) on domains. *)
val difference : t -> t -> t
    (** [difference big small] returns [big] {% $\setminus$ %} [small].
        [small] must be included in [big], otherwise the behaviour is
        unspecified (incorrect return value or exception raised). *)
val diff : t -> t -> t
    (** [diff d1 d2] returns [d1] {% $\setminus$ %} [d2], i.e. domain of
       elements in [d1] which are not in [d2]. *)
val minus : t -> t
  (** [minus d] returns the domain of opposite values of [d]. *)
val plus : t -> elt -> t
  (** [plus d n] translates a domain by [n]. *)
val times : t -> elt -> t
  (** [times d k] expands a domain by factor [k]. *)
val compare : t -> t -> elt
  (** [compare d1 d2] is a comparison function working first on the cardinal,
     then (if [d1] and [d2] have the same size) on the lexicographic order
     of the domains (expressed in extension). *)
val compare_elt : elt -> elt -> elt
  (** [compare_elt e1 e2] is a comparison function on elements of domains.
     Convenient to use the [Domain] module as a functor argument as in
     module [Var]{% ~\ref{module:Var}%}. *)
val disjoint : t -> t -> bool
  (** [disjoint d1 d2] tests whether [d1] and [d2] are disjoint. *)


(**/**)
val strictly_inf : elt -> elt -> bool

