(*
This file is part of the dpll(t) engine sammy
Copyright (C) 2004  The University of Iowa
Gesare Tinelli
Goerge Hagen
John Lee

This program 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.

This program 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.
*)

(* theory.mli *)

exception Incons

(** Theory interface module *)

class theory : 

  object

      method mark_base_level: unit
      method return_to_base_level: unit

      (** Type operations *)

      method boolType : Global.type_id
      (** Returns type_id for BOOLEAN *)

      method intType : Global.type_id
      (** Returns the type_id for INTEGER *)

      method realType : Global.type_id
      (** Returns type_id for REAL *)

      method decl_interpreted_type : string -> string list -> Global.type_id
      (** This is used to generate a non-basic interpreted type, such as:

          "ARRAY" (type,type)
          [arrayType x y]
          Returns type_id for an array with index type [x] and element type [y]

          "TUPLE" (type list)
          Returns a type id for a tuple of the listed types.

          "RECORD" (field list, type list)
          [recordType fields types] returns a record type

          "SUBRANGE" (id,id)

        NOTE: "TUPLE" is currently required if uninterpreted functions are 
        supported.
      *)

      method decType : string -> Global.type_id
      (** Declare a new uninterpreted type *)

      method functionType : Global.type_id -> Global.type_id -> Global.type_id
      (** [functionType r d] returns the type_id for a function with the 
      range type [r] (usually a tuple) and domain type [d] *)

      method get_function_type : string -> Global.type_id
      (** Returns the type_id associated with a function or variable symbol.
      This information would be initially set in the call to 
      [theory#decFunction] *)

      method get_tuple_literal_type : Global.term_id -> Global.type_id
      (** Returns the type_id associated with a tuple literal integer id *)

      method get_record_literal_type : Global.term_id -> Global.type_id
      (** Returns the type_id associated with a record literal integer id *)

      method is_bool : Global.term_id -> bool
      (** Returns [true] if the expression is a subtype of BOOLEAN *)


      (** Variables and constants *)

      method decNumeralConstant : string -> Global.term_id
      (** Returns the id for a REAL constant such as 5.6 or 347. *)

      method decRationalConstant : int -> int -> Global.term_id
      (** [decRationalConstant n d] 
      Returns the id for a rational constant [n/d] *)

      method decVariable : string -> Global.type_id -> Global.term_id
      (** Returns an id for a variable with the indicated name and type *)

      method neg_infinity : Global.term_id
      (** Returns id for negative infinity (for array index ranges) *)

      method pos_infinity : Global.term_id
      (** Returns id for positive infinity (for array index ranges) *)

      method true_id : Global.pred_id
      (** Returns id for TRUE *)


      (** Real number operations *)

      method appDiv : Global.term_id -> Global.term_id -> Global.term_id
      (** Returns term_id for x/y *)

      method appIntDiv : Global.term_id -> Global.term_id -> Global.term_id
      (** Returns term_id for x DIV y *)

      method appMinus : Global.term_id -> Global.term_id -> Global.term_id
      (** Returns term_id for x-y *)

      method appMod : Global.term_id -> Global.term_id -> Global.term_id
      (** Returns term_id for x%y *)

      method appMult : Global.term_id -> Global.term_id -> Global.term_id
      (** Returns term_id for x*y *)

      method appPlus : Global.term_id -> Global.term_id -> Global.term_id
      (** Returns term_id for x+y *)

      method appPow : Global.term_id -> Global.term_id -> Global.term_id
      (** Returns term_id for x^y *)

      method appUnaryMinus : Global.term_id -> Global.term_id
      (** Returns term_id for -x *)

      (** Real number relations *)

      method create_equals : Global.term_id -> Global.term_id -> Global.pred_id
      (** Returns the id for x=y *)

      method create_greater_than : 
        Global.term_id -> Global.term_id -> Global.pred_id
      (** Returns the id for x>y *)

      method create_greater_than_or_equals : 
        Global.term_id -> Global.term_id -> Global.pred_id
      (** Returns the id for x>=y *)

      method create_less_than : 
        Global.term_id -> Global.term_id -> Global.pred_id
      (** Returns the id for x<y *)

      method create_less_than_or_equals : 
        Global.term_id -> Global.term_id -> Global.pred_id
      (** Returns the id for x=<y *)

      method create_not_equals : 
        Global.term_id -> Global.term_id -> Global.pred_id
      (** Returns the id for x!=y *)



      (** Uninterpreted functions.  These functions will be first
      declared with a certain symbol and type, and then that must be applied 
      to a specific signature instance.  Functions are
      currently of f:x->y only, where x may be a TUPLE, a special
      interpreted type.  *)

      method decFunction : string -> Global.type_id -> Global.term_id
      (** Returns the id for a function symbol with the indicated type *)

      method appFunction : 
        Global.term_id -> Global.term_id list -> Global.term_id
      (** Returns term_id for f(t1,...,tn) *)

      method decl_interpreted_function : 
        string -> string list -> Global.term_id
      (** Returns the id for a specially interpreted function, including

          "ISINT" (id)
          Returns [true] if the expression is a subtype of INTEGER.
          (Note that this is actually a predicate.)

          "FLOOR" (id)
          Returns term_id for floor(x)

          "ARRAY_LOOKUP" (id,id)
          Returns the value of the nth element of an array

          "TUPLE_LOOKUP" (id,int)
           [tuple_select t n] returns the id of element [n] of tuple [t] 

          "RECORD_LOOKUP" (id,string)
          Returns the id of a record field's value

          "ARRAY_WRITE" (id,id,id)
          [write_array a i x] returns an id for the element [i] of [a] being
          changed to [x].

          "RECORD_WRITE" (id,string,id) 
          [rec_update r f x] returns an id for field [f] of [r] being
          changed to [x]. 

          "TUPLE_WRITE" (id,int,id)
          [tuple_update t n x] returns an id for element [n] of [t] being
          changed to [x].

      The parameters for these functions are all passed as strings, with
      id and int values extracted from such. 
      Interpreted functions are considered to have already be declared, so 
      this call is analogous to appFunction for uninterpreted functions.
      *)

      method decOldPred : string -> Global.pred_id -> unit
      (** Declare a previously uninterpreted (propositional) predicate 
      to the theory.  The id given must be unique.  This will only be called
      if an interpreted expression can take boolean arguments.
      It is to notify the theory of the existance of a boolean variable.
      The solver will supply a string identifier for the variable as
      well as a unique identifier.
      *)

     (** DPLL(T) interface methods *)

      method assert_neg :
        Global.pred_id -> (Global.pred_id * Global.status) list
      (** Asserts a pred's complement. Returns a list of changed predicates,
       not including the asserted pred. 
      The return list contains elements of the form (pred id, current status, 
      true)
      *)

      method assert_pos :
        Global.pred_id -> (Global.pred_id * Global.status) list
      (** Asserts a pred. Returns a list of changed predicates,
       not including the asserted pred. 
      The return list contains elements of the form (pred id, current status, 
      true)
      *)

      method check_consistency : unit
      (** Checks the consistency of the theory's constraint store.  Raises
      [Theory.Incons] if it is currently inconsistent. *)

      method entails : Global.pred_id -> bool
      (** Returns [true] if the theory entails a literal (signed pred id) *)

      method final_value : Global.pred_id -> bool
      (** Returns [true] if the predicate is a consequence of the
      theory + current model *)

      method implicants : Global.pred_id -> Global.pred_id list
      (** Returns the theory implicants for a literal (signed pred id). *)

      method next_id : int
      (** Returns a fresh id *)

      method retract_last : int -> unit
      (** Backtrack the theory n steps *)

      method status : Global.pred_id -> Global.status
      (** Reurns the theory status of a predicate.  Raises [Theory.Incons]
      if the constraint store is detected to be inconsistent. *)

      method reset : unit
      (** Resets the theory it its initial state, clearing it completely. *)


      method remove_expression : int -> unit
      (** Has the theory mark the indicated expression or op for deletion. 
      This function may be empty.
      Premature deletion will cause errors
      *)


      method get_expr_type : int -> int
      (** Returns the [type_id] of the expression indicated -- may be an
      expensive call *)

      method get_expr_base_type : int -> int
      (** Returns the largest supertype [type_id] of the expression indicated 
      -- may be an expensive call *)

      method get_type_base_type : int -> int
      (** Returns the largest supertype [type_id] of the type indicated 
      -- may be an expensive call *)


  end
