]> matita.cs.unibo.it Git - helm.git/blobdiff - helm/ocaml/cic/cicUniv.ml
Universes introduction
[helm.git] / helm / ocaml / cic / cicUniv.ml
diff --git a/helm/ocaml/cic/cicUniv.ml b/helm/ocaml/cic/cicUniv.ml
new file mode 100644 (file)
index 0000000..d76fde4
--- /dev/null
@@ -0,0 +1,345 @@
+(* Copyright (C) 2000, HELM Team.
+ * 
+ * This file is part of HELM, an Hypertextual, Electronic
+ * Library of Mathematics, developed at the Computer Science
+ * Department, University of Bologna, Italy.
+ * 
+ * HELM 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.
+ * 
+ * HELM 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 HELM; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA  02111-1307, USA.
+ * 
+ * For details, see the HELM World-Wide-Web page,
+ * http://cs.unibo.it/helm/.
+ *)
+
+(******************************************************************************)
+(*                                                                            *)
+(*                               PROJECT HELM                                 *)
+(*                                                                            *)
+(*                      Enrico Tassi <tassi@cs.unibo.it>                      *)
+(*                                 23/04/2004                                 *)
+(*                                                                            *)
+(* This module implements the aciclic graph of universes.                     *)
+(*                                                                            *)
+(******************************************************************************)
+
+(* 
+
+   todo:
+     - in add_eq there is probably no need of add_gt, simple @ the gt lists 
+     - the problem of duplicates in the 1steg gt/ge list if two of them are
+       add_eq may be "fixed" in some ways:
+        - lazy, do nothing on add_eq and eventually update the ge list 
+         on closure
+       - add a check_duplicates_after_eq function called by add_eq
+       - do something like rmap, add a list of canonical that point to us
+         so when we collapse we have the list of the canonical we may update
+     - don't use failure but another exception
+     
+*)
+
+(* ************************************************************************** *)
+(*  TYPES                                                                     *)
+(* ************************************************************************** *)
+type universe = int 
+
+type canonical_repr = {
+        mutable ge:universe list; 
+        mutable gt:universe list;
+       (* since we collapse we may need the reverse map *) 
+        mutable eq:universe list; 
+       (* the canonical representer *)
+        u:universe
+}
+
+module UniverseType = struct
+  type t = universe
+  let compare = Pervasives.compare
+end
+
+module MapUC = Map.Make(UniverseType)
+
+(* ************************************************************************** *)
+(*  Globals                                                                   *)
+(* ************************************************************************** *)
+
+let map = ref MapUC.empty 
+let used = ref (-1)
+
+(* ************************************************************************** *)
+(*  Helpers                                                                   *)
+(* ************************************************************************** *)
+
+(* create a canonical for [u] *)
+let mk_canonical u =
+  {u = u ; gt = [] ; ge = [] ; eq = [u] }
+
+(* give a new universe *)
+let fresh () = 
+  used := !used + 1;
+  map := MapUC.add !used (mk_canonical !used) !map;
+  !used
+  
+let reset () =
+  map := MapUC.empty;
+  used := -1
+  
+(* ************************************************************************** *)
+(*   Pretty printing                                                          *)
+(* ************************************************************************** *) 
+(* pp *)
+let string_of_universe = string_of_int
+
+(* pp *)
+let canonical_to_string c = 
+  let s_gt = 
+    List.fold_left (fun s u -> s ^ (string_of_universe u) ^ " ") "" c.gt in
+  let s_ge = 
+    List.fold_left (fun s u -> s ^ (string_of_universe u) ^ " ") "" c.ge in  
+  let s_eq =
+    List.fold_left (fun s u -> s ^ (string_of_universe u) ^ " ") "" c.eq in
+  let s_u = (string_of_universe c.u) in
+  "{ u:" ^ s_u ^ " ; gt:" ^ s_gt ^ " ; ge:" ^ s_ge ^ " ; eq: " ^ s_eq ^ "}"
+
+(* print the content of map *)
+let print_map () =
+  MapUC.iter (fun u c -> 
+   prerr_endline 
+    (" " ^ (string_of_universe u) ^ " -> " ^ (canonical_to_string c))) 
+  !map;
+  prerr_endline ""
+
+(* ************************************************************************** *)
+(*  The way we fail                                                           *)
+(* ************************************************************************** *)   
+(* we are doing bad *)
+let error s = 
+  (*prerr_endline " ======= Universe Inconsistency =========";
+  print_map ();*)
+  prerr_endline (" " ^ s ^ "\n");
+  failwith s
+
+(* ************************************************************************** *)
+(*  The real code                                                             *)
+(* ************************************************************************** *) 
+(* <--------> *)
+
+(* the canonical representer of the [u] equaliti class *)
+let repr u = 
+  try 
+    MapUC.find u !map
+  with
+    Not_found -> error ("map inconsistency, unbound " ^ (string_of_universe u))
+
+(* all the nodes we can ifer in the ge list of u *)
+let close_ge u =
+  let repr_u = repr u in
+  let rec close_ge_aux tofollow bag = 
+    match tofollow with
+      [] -> bag
+    | v::tl -> let repr_v = repr v in
+               if List.mem repr_v bag then (* avoid loops *)
+                 (close_ge_aux tl bag ) 
+               else
+                 (close_ge_aux (tl @ repr_v.ge) (repr_v::bag))
+                 (* we assume that v==u -> v \notin (repr u).ge *)
+  in
+  close_ge_aux repr_u.ge []
+
+(* all the nodes we can ifer in the gt list of u,
+   we must follow bot gt and ge arcs, but we must put in bag only 
+   the nodes that have a gt in theys path 
+*)
+let close_gt u =
+  let repr_u = repr u in
+  let rec close_gt_aux bag todo inspected =
+    (*print_all bag todo;Unix.sleep 1;*)
+    match todo with
+      [],[] -> bag
+    | [],p::may -> let repr_p = repr p in 
+                   if List.mem repr_p.u inspected then (* avoid loops *)
+                     close_gt_aux bag ([],may) inspected
+                   else 
+                     close_gt_aux bag (repr_p.gt,repr_p.ge @ may) 
+                      (repr_p.u::inspected)
+    | s::secure,may -> let repr_s = repr s in
+                       if List.mem repr_s.u inspected then (* avoid loops *)
+                         if List.mem repr_s bag then
+                           close_gt_aux bag (secure,may) inspected
+                         else
+                           (* even if we ave already inspected the node, now
+                              it is in the secure list so we want it in the bag 
+                           *)
+                           close_gt_aux (repr_s::bag) (secure,may) inspected
+                       else
+                         close_gt_aux ((repr_s)::bag) 
+                          (repr_s.gt @ repr_s.ge,may) (repr_s.u::inspected)
+  in
+  close_gt_aux [] (repr_u.gt,repr_u.ge) []
+  
+(* when we add an eq we have to change the mapping of u to c*)
+let remap u c =
+  let repr_u = repr u in
+  List.iter (fun u' -> if u <> u' then map := MapUC.remove u' !map) repr_u.eq;
+  List.iter (fun u' -> map := MapUC.add u' c !map) repr_u.eq
+
+(* we suspect that u and v are connected by a == implyed by two >= *)
+let rec collapse u v = 
+  let repr_u = repr u in
+  let repr_v = repr v in
+  let ge_v = close_ge v in
+  let ge_u = close_ge u in
+  if List.mem repr_u ge_v && List.mem repr_v ge_u then
+    add_eq u v
+
+(* we have to add u == v *)
+and add_eq u v = 
+  let repr_u = repr u in
+  let repr_v = repr v in
+  (* if we already have u == v then do nothing *)
+  if repr_u = repr_v then
+    () 
+  else
+    (* if we already have v > u then fail *)
+    let gt_v = close_gt v in
+    if List.mem repr_u gt_v then
+      error ("Asking for " ^ (string_of_universe u) ^ " == " ^ 
+            (string_of_universe v) ^ " but " ^ 
+            (string_of_universe v) ^ " > " ^ (string_of_universe u))
+    else 
+      (* if we already have u > v then fail *)
+      let gt_u = close_gt u in
+      if List.mem repr_v gt_u then           
+        error ("Asking for " ^ (string_of_universe u) ^ " == " ^ 
+              (string_of_universe v) ^ " but " ^ 
+              (string_of_universe u) ^ " > " ^ (string_of_universe v))
+      else
+        (* add the inherited > constraints *)
+        List.iter (fun v -> add_gt u v ) (*gt_v*) repr_v.gt;
+        (* add the inherited >= constraints *)
+        (* close_ge assumes that v==u -> v \notin (repr u).ge *)
+        repr_u.ge <- List.filter (fun x -> x <> u && x <> v) 
+         (repr_v.ge @ repr_u.ge);
+        (* mege the eq list, we assume they are disjuncted *)
+        repr_u.eq <- repr_u.eq @ repr_v.eq;
+        (* we have to remap all node represented by repr_v to repr_u *)
+        remap v repr_u;
+        (* FIXME: not sure this is what we have to do 
+                  think more to the list of suspected cicles
+        *)
+        List.iter (fun x -> collapse u x) repr_u.ge 
+    
+(* we have to add u >= v *)
+and add_ge u v =
+  let repr_u = repr u in
+  let repr_v = repr v in
+  (* if we already have u == v then do nothing *)
+  if repr_u = repr_v then
+    () 
+  else 
+    (* if we already have v > u then fail *)
+    let gt = close_gt v in
+    if List.memq repr_u gt then
+      error ("Asking for " ^ (string_of_universe u) ^ " >= " ^ 
+            (string_of_universe v) ^ " but " ^ 
+            (string_of_universe v) ^ " > " ^ (string_of_universe u))
+    else
+      (* it is now safe to add u >= v *)
+      repr_u.ge <- v::repr_u.ge;
+      (* but we may have introduced a cicle *)
+      collapse u v (* FIXME: not sure it is from u to v, think more. *)
+      
+(* we have to add u > v *)        
+and add_gt u v =
+  let repr_u = repr u in
+  let repr_v = repr v in
+  (* if we already have u == v then fail *)
+  if repr_u = repr_v then
+    error ("Asking for " ^ (string_of_universe u) ^ " > " ^ 
+          (string_of_universe v) ^ " but " ^ 
+          (string_of_universe u) ^ " == " ^ (string_of_universe v))
+  else 
+    (* if we already have u > v do nothing *)
+    let gt_u = close_gt u in
+    if List.memq repr_v gt_u then
+      () 
+    else
+      (* if we already have v > u then fail *)
+      let gt = close_gt v in
+      if List.memq repr_u gt then
+        error ("Asking for " ^ (string_of_universe u) ^ " > " ^ 
+              (string_of_universe v) ^ " but " ^ 
+              (string_of_universe v) ^ " > " ^ (string_of_universe u))
+      else
+        (* if we already have v >= u then fail *)
+        let ge = close_ge v in
+        if List.memq repr_u ge then
+          error ("Asking for " ^ (string_of_universe u) ^ " > " ^ 
+                (string_of_universe v) ^ " but " ^ 
+                (string_of_universe v) ^ " >= " ^ (string_of_universe u))
+        else
+          (* it is safe to add u > v *)
+          repr_u.gt <- v::repr_u.gt
+
+let add_gt u v =
+  try 
+    add_gt u v; true
+  with
+    exn -> false
+
+let add_ge u v =
+  try 
+    add_ge u v; true
+  with
+    exn -> false
+
+let add_eq u v =
+  try 
+    add_eq u v; true
+  with
+    exn -> false
+
+(* <--------> *)
+
+(* ************************************************************************** *)
+(*  To make tests                                                             *)
+(* ************************************************************************** *)
+
+(*
+let check_status_eq l =
+  let s = List.fold_left (fun s u -> s^(string_of_universe u) ^ ";") "" l in
+  let repr_u = repr (List.hd l) in
+  let rec check_status_eq_aux c =
+    match c with
+      [] -> print_endline (" Result check_status_eq["^s^"] = OK");true
+    | u::tl -> if repr u != repr_u then
+                 (print_endline (" Result check_status_eq["^s^"] = FAILED");
+                 print_endline ((string_of_universe u) ^ " != " ^ 
+                  (string_of_universe repr_u.u));
+                 print_map ();false)
+               else
+                 check_status_eq_aux tl
+  in
+  check_status_eq_aux (List.tl l)
+*)
+
+(* ************************************************************************** *)
+(*  Fake implementation                                                       *)
+(* ************************************************************************** *)
+
+(* <--------> *
+let add_ge u v = true
+let add_gt u v = true
+let add_eq u v = true
+* <--------> *)