type symbol = Symbol.symbol
type term = Term.term
type literal = Term.literal
type clause = Term.clause
type 'a data = 'a Term_indexing.data
type 'a iterator = 'a Term_indexing.iterator
exception ITERATOR_EMPTY = Term_indexing.ITERATOR_EMPTY
type hkey =
| Variable
| Parameter
| Symbol of symbol
type fterm =
hkey list
let hkey_equal (k1: hkey) (k2: hkey) : bool =
match k1, k2 with
| Variable, Variable ->
true
| Parameter, Parameter ->
true
| Symbol s1, Symbol s2 ->
Symbol.equal s1 s2
| _ ->
false
let hkey_hash (k1: hkey) : int =
match k1 with
| Variable ->
0
| Parameter ->
1
| Symbol s ->
2 + Symbol.id s
module Table =
Hashtbl.Make (
struct
type t = hkey
let equal = hkey_equal
let hash = hkey_hash
end
)
type 'data entry = {
term: term;
data: 'data;
}
type 'data leaf = {
mutable entries: 'data entry list;
fterm: fterm;
}
type 'data inner_node = {
mutable next: 'data node Table.t;
}
and 'data node = {
mutable prefix: fterm;
mutable variant: 'data variant;
}
and 'data variant =
| DtInnerNode of 'data inner_node
| DtLeafNode of 'data leaf
type 'data tree = {
mutable root: 'data node;
mutable size: int;
mutable found: 'data option;
}
type ('data, 'a) leaf_check = 'data leaf -> 'a list -> 'a list
let hkey_to_string hkey : string =
match hkey with
Symbol sym ->
(Symbol.name sym) ^ "/" ^ (string_of_int (Symbol.arity sym))
| Variable ->
"*U/0"
| Parameter ->
"*P/0"
let rec fterm_to_string x : string =
match x with
| [] ->
""
| h :: t ->
hkey_to_string h ^ " " ^ fterm_to_string t
let leaf_to_string (leaf: 'data leaf) (depth: int) : string =
let depth_prefix =
String.make (2 * depth) ' ' ^ string_of_int depth ^ ": "
in
String.concat ""
(List.map
(fun entry ->
depth_prefix ^ Term.term_to_string entry.term ^ "\n"
)
leaf.entries
)
let rec node_to_string (node: 'data node) (depth: int) : string =
let depth_prefix =
String.make (2 * depth) ' ' ^ string_of_int depth ^ ": "
in
depth_prefix ^
"prefix : " ^ fterm_to_string node.prefix ^ "\n" ^
match node.variant with
| DtInnerNode table ->
Table.fold
(fun hkey node acc ->
depth_prefix ^
"hkey : " ^ (hkey_to_string hkey) ^ "\n" ^
(node_to_string node (depth + 1)) ^
acc
)
table.next
""
| DtLeafNode leaf ->
leaf_to_string leaf depth
let tree_to_string (tree: 'data tree) : string =
node_to_string tree.root 0
let create_inner_node () = {
next = Table.create 8;
}
let create_node () = {
prefix = [];
variant = DtInnerNode (create_inner_node ());
}
let create_entry (term: term) (data: 'data) : 'data entry =
{
term = term;
data = data;
}
let create_tree () = {
root = create_node ();
size = 0;
found = None;
}
let clear (tree: 'data tree) : unit =
tree.root <- create_node ();
tree.size <- 0
let get_size (tree: 'data tree) : int =
tree.size
let inc_size (tree: 'data tree) : unit =
tree.size <- tree.size + 1
let dec_size (tree: 'data tree) : unit =
tree.size <- tree.size - 1
let hkey_arity (hkey: hkey) : int =
match hkey with
| Symbol s ->
Symbol.arity s
| _ ->
0
let term_hkey (term: Term.term ): hkey =
match term with
| Term.Var var ->
if Var.is_universal var then
Variable
else
Parameter
| Term.Const const ->
Symbol const
| Term.Func func ->
Symbol func.Term.symbol
let flatten_term (_term: term) : fterm =
let rec flatten_term' (term: term) (acc: fterm) : fterm =
match term with
| Term.Var var ->
if Var.is_universal var then
Variable :: acc
else
Parameter :: acc
| Term.Const symbol ->
Symbol symbol :: acc
| Term.Func func ->
let new_acc =
Array.fold_right
(fun term acc ->
flatten_term' term acc
)
func.Term.subterms
acc
in
Symbol func.Term.symbol :: new_acc
in
let flattened =
flatten_term' _term []
in
match flattened with
| _propositional_atom :: [] ->
flattened
| _ :: tail ->
tail
| [] ->
failwith "Discrimination_tree.flatten_term"
let rec skip_terms_fterm (fterm: fterm) (skip: int) : fterm =
if skip = 0 then
fterm
else
match fterm with
| hkey :: tail ->
skip_terms_fterm tail (skip - 1 + (hkey_arity hkey))
| _ ->
failwith "Discrimination_tree.skip_terms_fterm: Bad flattened term structure."
let rec skip_terms_fterm_partial (fterm: fterm) (skip: int) : fterm * int =
if skip = 0 then
fterm, 0
else
match fterm with
| hkey :: tail ->
skip_terms_fterm_partial tail (skip - 1 + (hkey_arity hkey))
| [] ->
[], skip
let rec shorten_fterm (prefix: fterm) (fterm: fterm) : fterm =
match prefix, fterm with
| [], _ ->
fterm
| xh :: xt, yh :: yt when
hkey_equal xh yh ->
shorten_fterm xt yt
| _ ->
raise Exit
let find_prefix (_x: fterm) (_y: fterm) : fterm * fterm * fterm =
let rec find_prefix' (prefix: fterm) (x: fterm) (y: fterm) : fterm * fterm * fterm =
match x, y with
| xh :: xt, yh :: yt when
hkey_equal xh yh ->
find_prefix' (xh :: prefix) xt yt
| _ ->
List.rev prefix, x, y
in
find_prefix' [] _x _y
let rec fterm_equal (x: fterm) (y: fterm) : bool =
x == y
||
match x, y with
| [], [] ->
true
| xh :: xt, yh :: yt when
hkey_equal xh yh ->
fterm_equal xt yt
| _ ->
false
let rec fterm_equal_generalization ~(p_preserving:bool) (x: fterm) (y: fterm) : bool =
match x, y with
| [], [] ->
true
| xh :: xt, yh :: yt ->
if hkey_equal xh yh then begin
fterm_equal_generalization ~p_preserving:p_preserving xt yt
end
else if
xh = Variable
||
(
not p_preserving
&&
xh = Parameter
)
then begin
fterm_equal_generalization ~p_preserving:p_preserving xt (skip_terms_fterm y 1)
end
else begin
false
end
| _ ->
print_endline (fterm_to_string x);
print_endline (fterm_to_string y);
failwith "Discrimination_tree.fterm_equal_generalization: Bad flattened term structure."
exception FOUND
let set_found (tree: 'data tree) (data: 'data) : unit =
tree.found <- Some data
let get_found (tree: 'data tree) : 'data =
match tree.found with
| None ->
failwith "Discrimination_tree.get_found"
| Some data ->
tree.found <- None;
data
let rec add_term ~(no_duplicates: bool) (_data: 'data data)
(entry: 'data entry) (new_term: fterm) (fterm: fterm) (node: 'data inner_node) : bool =
match fterm with
| [] ->
failwith "discrimination_tree:add_term: Bad index structure 1."
| hkey :: tail ->
begin
try
let next =
Table.find node.next hkey
in
begin
try
let tail =
shorten_fterm next.prefix tail
in
match next.variant with
| DtLeafNode entries ->
if Const.debug && tail != [] then
failwith "add_term";
if no_duplicates then begin
if
List.exists
(fun entry' ->
Term.term_equal entry.term entry'.term
)
entries.entries
then
false
else begin
entries.entries <- entry :: entries.entries;
true
end
end
else begin
entries.entries <- entry :: entries.entries;
true
end
| DtInnerNode table1 ->
add_term ~no_duplicates:no_duplicates _data entry new_term tail table1
with
| Exit ->
let common_prefix, prefix', fterm' =
find_prefix next.prefix tail
in
let new_next = {
prefix = List.tl prefix';
variant = next.variant;
}
in
let new_leaf_node = {
prefix = List.tl fterm';
variant = DtLeafNode {
entries = [ entry ];
fterm = new_term;
}
}
in
let common_inner_node =
create_inner_node ()
in
Table.add common_inner_node.next (List.hd prefix') new_next;
Table.add common_inner_node.next (List.hd fterm') new_leaf_node;
next.prefix <- common_prefix;
next.variant <- DtInnerNode common_inner_node;
true
end
with
| Not_found ->
let new_leaf = {
prefix = tail;
variant = DtLeafNode {
entries = [ entry ];
fterm = new_term;
}
}
in
Table.add node.next hkey new_leaf;
true
end
let remove_leaf ~(equal: bool)
(term: term) (data: 'data option) (_data: 'data data)
(leaf: 'data leaf) : unit =
let rec list_remove_variant' (entries: 'data entry list) : 'data entry list =
match entries with
| [] ->
raise Not_found
| entry :: tail ->
if
(equal && Term.term_equal entry.term term)
||
(not equal && Term.are_terms_variants entry.term term)
then begin
match data with
| Some termdata when
not (_data#is_equal entry.data termdata) ->
entry :: list_remove_variant' tail
| _ ->
tail
end
else
entry :: list_remove_variant' tail
in
leaf.entries <- list_remove_variant' leaf.entries
let rec remove_node ~(equal: bool) (term: term) (fterm: fterm) (data: 'data option) (_data: 'data data) (node: 'data node) : bool =
try
let fterm =
shorten_fterm node.prefix fterm
in
match node.variant with
| DtInnerNode table ->
begin
match fterm with
| [] ->
raise (Failure "Discrimination_tree.remove_node: Bad index structure.")
| hkey :: fterm1 ->
begin
try
let empty =
remove_node ~equal:equal term fterm1 data _data (Table.find table.next hkey)
in
if empty then begin
Table.remove table.next hkey;
Table.length table.next == 0;
end
else begin
false
end
with
| Not_found ->
raise Not_found
end
end
| DtLeafNode leaf ->
if fterm != [] then
failwith "remove_node";
remove_leaf ~equal:equal term data _data leaf;
(leaf.entries = [])
with
| Exit ->
raise Not_found
let remove_variant ~(equal:bool) (tree: 'data tree) (term: term) (data: 'data option) (_data: 'data data) : bool =
let fterm =
flatten_term term
in
try
ignore (remove_node ~equal:equal term fterm data _data tree.root : bool);
dec_size tree;
true
with
| Not_found ->
false
let rec iter (func: term -> 'data -> unit) (node: 'data node) : unit =
match node.variant with
| DtInnerNode table ->
Table.iter
(fun _ node' ->
iter func node')
table.next
| DtLeafNode entries ->
List.iter
(fun entry -> func entry.term entry.data )
entries.entries
let rec fold (func: 'a -> term -> 'data -> 'a) (acc: 'a) (node: 'data node) : 'a =
match node.variant with
| DtInnerNode table ->
Table.fold
(fun _ node acc ->
fold func acc node
)
table.next
acc
| DtLeafNode entries ->
List.fold_left
(fun acc entry ->
func acc entry.term entry.data
)
acc
entries.entries
let create_leaf_check
?(find_all: bool = true)
(tree: 'data tree)
(check_fterm: fterm -> bool)
(check_term: term -> bool)
(leaf: 'data leaf)
(acc: 'data list)
: 'data list =
if not (check_fterm leaf.fterm) then begin
acc
end
else begin
List.fold_left
(fun acc entry ->
if check_term entry.term then begin
if find_all then
entry.data :: acc
else begin
set_found tree entry.data;
raise FOUND;
end
end
else
acc
)
acc
leaf.entries
end
let create_leaf_check_subst
(_tree: 'data tree)
(check_fterm: fterm -> bool)
(check_term: term -> Subst.subst)
(leaf: 'data leaf)
(acc: ('data * Subst.subst) list)
: ('data * Subst.subst) list =
if not (check_fterm leaf.fterm) then begin
acc
end
else begin
List.fold_left
(fun acc entry ->
try
let subst =
check_term entry.term
in
(entry.data, subst) :: acc
with
| Unification.UNIFICATION_FAIL ->
acc
)
acc
leaf.entries
end
let descend_variant ~(p_preserving: bool)
(func: p_preserving:bool -> ('data, 'a) leaf_check -> 'a list -> 'fterm -> 'data node -> fterm -> 'a list)
(leaf_check: ('data, 'a) leaf_check)
(acc: 'a list)
(hkey: hkey) (tail: fterm) (table: 'data inner_node)
: 'a list
=
let node =
try
Some (Table.find table.next hkey)
with
| Not_found ->
None
in
match node with
| None ->
acc
| Some node' ->
func ~p_preserving:p_preserving leaf_check acc tail node' node'.prefix
let descend_generalized ~(p_preserving: bool)
(func: p_preserving:bool -> ('data, 'a) leaf_check -> 'a list -> 'fterm -> 'data node -> fterm -> 'a list)
(leaf_check: ('data, 'a) leaf_check)
(acc: 'a list)
(hkey: hkey) (fterm: fterm) (table: 'data inner_node)
: 'a list
=
let node =
try
Some (Table.find table.next hkey)
with
| Not_found ->
None
in
match node with
| None ->
acc
| Some node' ->
func ~p_preserving:p_preserving leaf_check acc (skip_terms_fterm fterm 1) node' node'.prefix
let rec descend_instance ~(p_preserving:bool)
(func: p_preserving:bool -> ('data, 'a) leaf_check -> 'a list -> 'fterm -> 'data node -> fterm -> 'a list)
(leaf_check: ('data, 'a) leaf_check)
(acc: 'a list)
(query_tail: fterm) (table: 'data inner_node) (skip: int)
: 'a list
=
Table.fold
(fun hkey node acc ->
let skip' =
skip - 1 + (hkey_arity hkey)
in
let prefix, skip' =
skip_terms_fterm_partial node.prefix skip'
in
if skip' = 0 then
func ~p_preserving:p_preserving leaf_check acc query_tail node prefix
else
match node.variant with
| DtLeafNode _ ->
failwith "Discrimination_tree.descend_instance"
| DtInnerNode table' ->
descend_instance ~p_preserving:p_preserving func leaf_check acc query_tail table' skip'
)
table.next
acc
let rec find_variants (leaf_check: ('data, 'data) leaf_check)
(fterm: fterm) (node: 'data node) : 'data list =
try
let fterm =
shorten_fterm node.prefix fterm
in
begin
match fterm, node.variant with
| hkey :: fterm', DtInnerNode table ->
begin
try
let node' =
Table.find table.next hkey
in
find_variants leaf_check fterm' node'
with
| Not_found ->
[]
end
| [], DtLeafNode leaf ->
leaf_check leaf []
| _ ->
failwith "Discrimination_tree.find_variants"
end
with
| Exit ->
[]
let rec find_generalizations ~(p_preserving: bool)
(leaf_check: ('data, 'data) leaf_check) (acc: 'data list)
(query_fterm: fterm) (node: 'data node) (tree_fterm: fterm) : 'data list =
match query_fterm, tree_fterm, node.variant with
| query_key :: query_tail, tree_key :: tree_tail, _ when
hkey_equal query_key tree_key ->
find_generalizations ~p_preserving:p_preserving
leaf_check acc
query_tail node tree_tail
| [], [], DtLeafNode leaf ->
leaf_check leaf acc
| Symbol _ as hkey :: query_tail, [], DtInnerNode table ->
let acc =
descend_variant ~p_preserving:p_preserving
find_generalizations leaf_check acc
hkey query_tail table
in
let acc =
descend_generalized ~p_preserving:p_preserving
find_generalizations leaf_check acc
Variable query_fterm table
in
if p_preserving then
acc
else
descend_generalized ~p_preserving:p_preserving
find_generalizations leaf_check acc
Parameter query_fterm table
| Variable :: query_tail, [], DtInnerNode table ->
let acc =
descend_variant ~p_preserving:p_preserving
find_generalizations leaf_check acc
Variable query_tail table
in
if p_preserving then
acc
else
descend_variant ~p_preserving:p_preserving
find_generalizations leaf_check acc
Parameter query_tail table
| Parameter :: query_tail, [], DtInnerNode table ->
let acc =
descend_variant ~p_preserving:p_preserving
find_generalizations leaf_check acc
Variable query_tail table
in
descend_variant ~p_preserving:p_preserving
find_generalizations leaf_check acc
Parameter query_tail table
| _ :: _, Variable :: tree_tail, _ ->
find_generalizations ~p_preserving:p_preserving
leaf_check acc
(skip_terms_fterm query_fterm 1) node tree_tail
| _ :: _, Parameter :: tree_tail, _ when not p_preserving ->
find_generalizations ~p_preserving:p_preserving
leaf_check acc
(skip_terms_fterm query_fterm 1) node tree_tail
| _ :: _, _ :: _, _ ->
acc
| [], _ :: _, _ ->
failwith "Discrimination_tree.find_generalizations 1"
| _ :: _, [], DtLeafNode _ ->
failwith "Discrimination_tree.find_generalizations 2"
| [], [], DtInnerNode _ ->
failwith "Discrimination_tree.find_generalizations 3"
let rec find_unifiables ~(p_preserving: bool)
(leaf_check: ('data, 'data) leaf_check) (acc: 'data list)
(query_fterm: fterm) (node: 'data node) (tree_fterm: fterm) : 'data list =
match query_fterm, tree_fterm, node.variant with
| query_key :: query_tail, tree_key :: tree_tail, _ when
hkey_equal query_key tree_key ->
find_unifiables ~p_preserving:p_preserving
leaf_check acc
query_tail node tree_tail
| [], [] , DtLeafNode leaf ->
leaf_check leaf acc
| Symbol _ as hkey :: query_tail, [], DtInnerNode table ->
let acc =
descend_variant ~p_preserving:p_preserving
find_unifiables leaf_check acc
hkey query_tail table
in
let acc =
descend_generalized ~p_preserving:p_preserving
find_unifiables leaf_check acc
Variable query_fterm table
in
if p_preserving then
acc
else
descend_generalized ~p_preserving:p_preserving
find_unifiables leaf_check acc
Parameter query_fterm table
| Variable :: query_tail, [], DtInnerNode table ->
descend_instance ~p_preserving:p_preserving
find_unifiables leaf_check acc
query_tail table 1
| Parameter :: query_tail, [], DtInnerNode table ->
if p_preserving then begin
let acc =
descend_variant ~p_preserving:p_preserving
find_unifiables leaf_check acc
Variable query_tail table
in
descend_variant ~p_preserving:p_preserving
find_unifiables leaf_check acc
Parameter query_tail table
end
else begin
descend_instance ~p_preserving:p_preserving
find_unifiables leaf_check acc
query_tail table 1
end
| Variable :: query_tail, _ :: _, _ ->
let tree_fterm', skip =
skip_terms_fterm_partial tree_fterm 1
in
if skip = 0 then
find_unifiables ~p_preserving:p_preserving
leaf_check acc
query_tail node tree_fterm'
else
begin
match node.variant with
| DtInnerNode inner_node ->
descend_instance ~p_preserving:p_preserving
find_unifiables leaf_check acc
query_tail inner_node skip
| DtLeafNode _ ->
failwith "find_unifiables 3"
end
| _ :: _, Variable :: tree_tail, _ ->
find_unifiables ~p_preserving:p_preserving
leaf_check acc
(skip_terms_fterm query_fterm 1) node tree_tail
| Parameter :: query_tail, _ :: _, _ ->
if p_preserving then
acc
else
let tree_fterm', skip =
skip_terms_fterm_partial tree_fterm 1
in
if skip = 0 then
find_unifiables ~p_preserving:p_preserving
leaf_check acc
query_tail node tree_fterm'
else
begin
match node.variant with
| DtInnerNode inner_node ->
descend_instance ~p_preserving:p_preserving
find_unifiables leaf_check acc
query_tail inner_node skip
| DtLeafNode _ ->
failwith "find_unifiables 5"
end
| _ :: _, Parameter :: tree_tail, _ ->
if p_preserving then
acc
else
find_unifiables ~p_preserving:p_preserving
leaf_check acc
(skip_terms_fterm query_fterm 1) node tree_tail
| _ :: _, _ :: _, _ ->
acc
| [], _ :: _, _ ->
failwith "Discrimination_tree.find_unifiables 1"
| [], [], DtInnerNode _ ->
failwith "Discrimination_tree.find_unifiables"
| _ :: _, [], DtLeafNode _ ->
failwith "Discrimination_tree.find_unifiables 2"
let rec find_unifiables_subst ~(p_preserving: bool)
leaf_check (acc: ('data * Subst.subst) list)
(query_fterm: fterm) (node: 'data node) (tree_fterm: fterm) : ('data * Subst.subst) list =
match query_fterm, tree_fterm, node.variant with
| query_key :: query_tail, tree_key :: tree_tail, _ when
hkey_equal query_key tree_key ->
find_unifiables_subst ~p_preserving:p_preserving
leaf_check acc
query_tail node tree_tail
| [], [] , DtLeafNode leaf ->
leaf_check leaf acc
| Symbol _ as hkey :: query_tail, [], DtInnerNode table ->
let acc =
descend_variant ~p_preserving:p_preserving
find_unifiables_subst leaf_check acc
hkey query_tail table
in
let acc =
descend_generalized ~p_preserving:p_preserving
find_unifiables_subst leaf_check acc
Variable query_fterm table
in
if p_preserving then
acc
else
descend_generalized ~p_preserving:p_preserving
find_unifiables_subst leaf_check acc
Parameter query_fterm table
| Variable :: query_tail, [], DtInnerNode table ->
descend_instance ~p_preserving:p_preserving
find_unifiables_subst leaf_check acc
query_tail table 1
| Parameter :: query_tail, [], DtInnerNode table ->
if p_preserving then begin
let acc =
descend_variant ~p_preserving:p_preserving
find_unifiables_subst leaf_check acc
Variable query_tail table
in
descend_variant ~p_preserving:p_preserving
find_unifiables_subst leaf_check acc
Parameter query_tail table
end
else begin
descend_instance ~p_preserving:p_preserving
find_unifiables_subst leaf_check acc
query_tail table 1
end
| Variable :: query_tail, _ :: _, _ ->
let tree_fterm', skip =
skip_terms_fterm_partial tree_fterm 1
in
if skip = 0 then
find_unifiables_subst ~p_preserving:p_preserving
leaf_check acc
query_tail node tree_fterm'
else
begin
match node.variant with
| DtInnerNode inner_node ->
descend_instance ~p_preserving:p_preserving
find_unifiables_subst leaf_check acc
query_tail inner_node skip
| DtLeafNode _ ->
failwith "find_unifiables 3"
end
| _ :: _, Variable :: tree_tail, _ ->
find_unifiables_subst ~p_preserving:p_preserving
leaf_check acc
(skip_terms_fterm query_fterm 1) node tree_tail
| Parameter :: query_tail, _ :: _, _ ->
if p_preserving then
acc
else
let tree_fterm', skip =
skip_terms_fterm_partial tree_fterm 1
in
if skip = 0 then
find_unifiables_subst ~p_preserving:p_preserving
leaf_check acc
query_tail node tree_fterm'
else
begin
match node.variant with
| DtInnerNode inner_node ->
descend_instance ~p_preserving:p_preserving
find_unifiables_subst leaf_check acc
query_tail inner_node skip
| DtLeafNode _ ->
failwith "find_unifiables 5"
end
| _ :: _, Parameter :: tree_tail, _ ->
if p_preserving then
acc
else
find_unifiables_subst ~p_preserving:p_preserving
leaf_check acc
(skip_terms_fterm query_fterm 1) node tree_tail
| _ :: _, _ :: _, _ ->
acc
| [], _ :: _, _ ->
failwith "Discrimination_tree.find_unifiables 1"
| [], [], DtInnerNode _ ->
failwith "Discrimination_tree.find_unifiables"
| _ :: _, [], DtLeafNode _ ->
failwith "Discrimination_tree.find_unifiables 2"
let rec find_instances ~(p_preserving: bool)
(leaf_check: ('data, 'data) leaf_check) (acc: 'data list)
(query_fterm: fterm) (node: 'data node) (tree_fterm: fterm) : 'data list =
match query_fterm, tree_fterm, node.variant with
| query_key :: query_tail, tree_key :: tree_tail, _ when
hkey_equal query_key tree_key ->
find_instances ~p_preserving:p_preserving
leaf_check acc
query_tail node tree_tail
| [], [], DtLeafNode leaf ->
leaf_check leaf acc
| Symbol _ as hkey :: query_tail, [], DtInnerNode table ->
descend_variant ~p_preserving:p_preserving
find_instances leaf_check acc
hkey query_tail table
| Variable :: query_tail, [], DtInnerNode table ->
descend_instance ~p_preserving:p_preserving
find_instances leaf_check acc
query_tail table 1
| Parameter :: query_tail, [], DtInnerNode table ->
if p_preserving then begin
descend_variant ~p_preserving:p_preserving
find_instances leaf_check acc
Parameter query_tail table
end
else begin
descend_instance ~p_preserving:p_preserving
find_instances leaf_check acc
query_tail table 1
end
| Variable :: query_tail, _ :: _, _ ->
let tree_fterm', skip =
skip_terms_fterm_partial tree_fterm 1
in
if skip = 0 then
find_instances ~p_preserving:p_preserving
leaf_check acc
query_tail node tree_fterm'
else
begin
match node.variant with
| DtInnerNode inner_node ->
descend_instance ~p_preserving:p_preserving
find_instances leaf_check acc
query_tail inner_node skip
| DtLeafNode _ ->
failwith "find_instances 3"
end
| Parameter :: query_tail, _ :: _, _ ->
if p_preserving then
acc
else
let tree_fterm', skip =
skip_terms_fterm_partial tree_fterm 1
in
if skip = 0 then
find_instances ~p_preserving:p_preserving
leaf_check acc
query_tail node tree_fterm'
else
begin
match node.variant with
| DtInnerNode inner_node ->
descend_instance ~p_preserving:p_preserving
find_instances leaf_check acc
query_tail inner_node skip
| DtLeafNode _ ->
failwith "find_instances 4"
end
| _ :: _, _ :: _, _ ->
acc
| [], _ :: _, _ ->
failwith "Discrimination_tree.find_instances 1"
| [], [], DtInnerNode _ ->
failwith "Discrimination_tree.find_instance 1"
| _ :: _, [], DtLeafNode _ ->
failwith "Discrimination_tree.find_instance 2"
let rec find_shielding ~(p_preserving: bool)
(leaf_check: ('data, 'data) leaf_check) (acc: 'data list)
(query_fterm: fterm) (node: 'data node) (tree_fterm: fterm) : 'data list =
match query_fterm, tree_fterm, node.variant with
| query_key :: query_tail, tree_key :: tree_tail, _ when
hkey_equal query_key tree_key ->
find_shielding ~p_preserving:p_preserving
leaf_check acc
query_tail node tree_tail
| [], [], DtLeafNode leaf ->
leaf_check leaf acc
| Symbol _ as hkey :: query_tail, [], DtInnerNode table ->
let acc =
descend_variant ~p_preserving:p_preserving
find_shielding leaf_check acc
hkey query_tail table
in
descend_generalized ~p_preserving:p_preserving
find_shielding leaf_check acc
Variable query_fterm table
| Variable :: query_tail, [], DtInnerNode table
| Parameter :: query_tail, [], DtInnerNode table ->
descend_instance ~p_preserving:p_preserving
find_shielding leaf_check acc
query_tail table 1
| Variable :: query_tail, Parameter :: tree_tail, _
| Parameter :: query_tail, Variable :: tree_tail, _ ->
find_shielding ~p_preserving:p_preserving
leaf_check acc
query_tail node tree_tail
| Variable :: query_tail, Symbol _ :: _, _
| Parameter :: query_tail, Symbol _ :: _, _ ->
let tree_fterm', skip =
skip_terms_fterm_partial tree_fterm 1
in
if skip = 0 then
find_shielding ~p_preserving:p_preserving
leaf_check acc
query_tail node tree_fterm'
else
begin
match node.variant with
| DtInnerNode inner_node ->
descend_instance ~p_preserving:p_preserving
find_shielding leaf_check acc
query_tail inner_node skip
| DtLeafNode _ ->
failwith "find_shielding 3"
end
| _ :: _, Variable :: tree_tail, _ ->
find_shielding ~p_preserving:p_preserving
leaf_check acc
(skip_terms_fterm query_fterm 1) node tree_tail
| _ :: _, _ :: _, _ ->
acc
| [], _ :: _, _ ->
failwith "Discrimination_tree.find_instances 1"
| [], [], DtInnerNode _ ->
failwith "Discrimination_tree.find_shielding"
| _, [], DtLeafNode _ ->
failwith "Discrimination_tree.find_shielding 2"
class ['data] predicate_index (__productivity: bool) (__data: 'data data) =
object (self)
val _data = __data
val _productivity = __productivity
val _tree: 'data tree = create_tree ()
method clear =
clear _tree
method size =
get_size _tree
method add ?(no_duplicates: bool = false) (term: term) (data: 'data) : unit =
match _tree.root.variant with
| DtInnerNode table ->
let fterm =
flatten_term term
in
let added =
if _productivity then
add_term ~no_duplicates:no_duplicates _data (create_entry term data) fterm fterm table
else
add_term ~no_duplicates:no_duplicates _data (create_entry term data) [] fterm table;
in
if added then begin
inc_size _tree;
end;
| _ ->
raise (Failure "discrimination_tree:add: Bad index toplevel type.")
method iter (func: term -> 'data -> unit) : unit =
iter func _tree.root
method fold:
'a. ('a -> term -> 'data -> 'a) -> 'a -> 'a =
fun func acc ->
fold func acc _tree.root
method remove (term: term) (data: 'data option) : bool =
if get_size _tree = 0 then
false
else
remove_variant ~equal:true _tree term data _data
method find_all_variants (term: term) : 'data list =
if get_size _tree = 0 then
[]
else
find_variants
(create_leaf_check ~find_all:true
_tree
(fun _ -> true)
(Term.are_terms_variants term)
)
(flatten_term term)
_tree.root
method find (term: term) : 'data option =
if get_size _tree = 0 then
None
else
try
ignore (
find_variants
(create_leaf_check ~find_all:false
_tree
(fun _ -> true)
(Term.term_equal term)
)
(flatten_term term)
_tree.root
: 'data list);
None
with FOUND ->
Some (get_found _tree)
method private find_generalizations' ~(find_all: bool) ~(p_preserving: bool) (term: term) : 'data list =
find_generalizations ~p_preserving:p_preserving
(create_leaf_check
~find_all:find_all
_tree
(fun _ -> true)
(Unification.is_term_instance ~p_preserving:p_preserving term)
)
[]
(flatten_term term)
_tree.root
_tree.root.prefix
method find_all_generalizations ~(p_preserving: bool) (term: term) : 'data list =
if get_size _tree = 0 then
[]
else
self#find_generalizations' ~find_all:true ~p_preserving:p_preserving term
method find_generalization ~(p_preserving: bool) (term: term) : 'data option =
if get_size _tree = 0 then
None
else
try
ignore(
self#find_generalizations' ~find_all:false ~p_preserving:p_preserving term
: 'data list);
None
with FOUND ->
Some (get_found _tree)
method private find_unifiables' ~(find_all: bool) ~(p_preserving: bool) (term: term) : 'data list =
find_unifiables ~p_preserving:p_preserving
(create_leaf_check
~find_all:find_all
_tree
(fun _ -> true)
(Unification.are_terms_unifiable ~p_preserving:p_preserving term)
)
[]
(flatten_term term)
_tree.root
_tree.root.prefix
method find_all_unifiable ~(p_preserving: bool) (term: term) : 'data list =
if get_size _tree = 0 then
[]
else
self#find_unifiables' ~find_all:true ~p_preserving:p_preserving term
method find_unifiable ~(p_preserving: bool) (term: term) : 'data option =
if _tree.size == 0 then
None
else
try
ignore(
self#find_unifiables' ~find_all:false ~p_preserving:p_preserving term
: 'data list);
None
with FOUND ->
Some (get_found _tree)
method find_all_unifiable_subst ~(p_preserving: bool) (term: term) : ('data * Subst.subst) list =
if get_size _tree = 0 then
[]
else
find_unifiables_subst ~p_preserving:p_preserving
(create_leaf_check_subst
_tree
(fun _ -> true)
(fun tree_term ->
Unification.unify_terms ~recompute:false ~p_preserving:p_preserving
term Term_indexing.query_offset tree_term Term_indexing.index_offset)
)
[]
(flatten_term term)
_tree.root
_tree.root.prefix
method private find_instances' ~(find_all: bool) ~(p_preserving: bool) (term: term) : 'data list =
find_instances ~p_preserving:p_preserving
(create_leaf_check
~find_all:find_all
_tree
(fun _ -> true)
(fun tree_term ->
Unification.is_term_generalization ~p_preserving:p_preserving term tree_term
)
)
[]
(flatten_term term)
_tree.root
_tree.root.prefix
method find_all_instances ~(p_preserving: bool) (term: term) : 'data list =
if get_size _tree = 0 then
[]
else
self#find_instances' ~find_all:true ~p_preserving:p_preserving term
method find_instance ~(p_preserving: bool) (term: term) : 'data option =
if get_size _tree = 0 then
None
else
try
ignore(
self#find_instances' ~find_all:false ~p_preserving:p_preserving term
: 'data list);
None
with FOUND ->
Some (get_found _tree)
method find_strongly_shielding (producer: term) (produced: term) : 'data option =
if not _productivity then
failwith "Discrimination_tree: productivity not enabled"
else if get_size _tree = 0 then
None
else
let fterm_produced =
flatten_term produced
in
try
ignore(
find_instances ~p_preserving:false
(create_leaf_check
~find_all:false
_tree
(fun leaf_fterm -> fterm_equal_generalization ~p_preserving:false leaf_fterm fterm_produced)
(fun tree_term ->
(Term.term_equal tree_term produced)
||
(
not (Term.term_equal producer tree_term)
&&
Unification.is_term_instance produced tree_term
&&
Unification.is_term_generalization producer tree_term
)
)
)
[]
(flatten_term producer)
_tree.root
_tree.root.prefix
: 'data list);
None
with FOUND ->
Some (get_found _tree)
method private shielding_entry_check (producer: term) (produced: term) (tree_term: term) : bool =
(Term.term_equal tree_term produced)
||
(
not (Term.term_equal tree_term producer)
&&
Unification.is_term_instance produced tree_term
&&
(
try
let subst =
Unification.unify_terms ~recompute:false
producer Term_indexing.query_offset
tree_term Term_indexing.index_offset
in
Subst.is_p_renaming subst Term_indexing.index_offset
with
| Unification.UNIFICATION_FAIL ->
false
)
)
method private find_shielding' ~(find_all: bool) (producer: term) (produced: term) : 'data list =
let fterm_produced =
flatten_term produced
in
find_shielding ~p_preserving:false
(create_leaf_check
~find_all:find_all
_tree
(fun leaf_fterm -> fterm_equal_generalization ~p_preserving:false leaf_fterm fterm_produced)
(self#shielding_entry_check producer produced)
)
[]
(flatten_term producer)
_tree.root
_tree.root.prefix
method find_all_shielding (producer: term) (produced: term) : 'data list =
if not _productivity then
failwith "Discrimination_tree: productivity not enabled"
else if get_size _tree = 0 then
[]
else
self#find_shielding' ~find_all:true producer produced
method find_shielding (producer: term) (produced: term) : 'data option =
if not _productivity then
failwith "Discrimination_tree: productivity not enabled"
else if get_size _tree = 0 then
None
else
try
ignore(
self#find_shielding' ~find_all:false producer produced
: 'data list);
None
with FOUND ->
Some (get_found _tree)
method get_generalization_iterator ~(p_preserving: bool) (term: term) : 'data iterator =
let generalizations =
self#find_all_generalizations ~p_preserving:p_preserving term
in
object (_iterator)
val mutable _elements = generalizations
method is_empty =
match _elements with
| [] -> true
| _ -> false
method next =
match _elements with
| [] ->
raise ITERATOR_EMPTY
| element :: tail ->
_elements <- tail;
element
end
method get_shielding_iterator (producer: term) (produced: term) : 'data iterator =
object (iterator)
val _producer_fterm = flatten_term producer
val _produced_fterm = flatten_term produced
val mutable _nodes: (fterm * 'data node * fterm) list = []
val mutable _entries: 'entry list = []
val mutable _shielding: 'data option = None
initializer
if not _productivity then
failwith "Discrimination_tree: productivity not enabled"
else if get_size _tree > 0 then
iterator#save_node _producer_fterm _tree.root _tree.root.prefix
method private save_node (query_ftail: fterm) (node: 'data node) (tree_ftail: fterm) =
_nodes <- (query_ftail, node, tree_ftail) :: _nodes
method private save_leaf (leaf: 'data leaf) =
if fterm_equal_generalization ~p_preserving:false leaf.fterm _produced_fterm then begin
_entries <- _entries @ leaf.entries;
end
method is_empty =
match _shielding with
| Some _ ->
false
| None ->
begin
match _entries with
| entry :: tail ->
_entries <- tail;
if self#shielding_entry_check producer produced entry.term then begin
_shielding <- Some entry.data;
end;
iterator#is_empty
| [] ->
begin
match _nodes with
| (query_fterm, node, tree_fterm) :: tail ->
_nodes <- tail;
iterator#advance query_fterm node tree_fterm;
iterator#is_empty
| [] ->
true
end
end
method next =
if iterator#is_empty then
raise ITERATOR_EMPTY
else
match _shielding with
| None ->
failwith "Discrimination_tree.get_shielding_iterator.next"
| Some shielding ->
_shielding <- None;
shielding
method private advance (query_fterm: fterm) (node: 'data node) (tree_fterm: fterm) : unit =
match query_fterm, tree_fterm, node.variant with
| [], _ :: _, _ ->
failwith "Discrimination_tree.get_shielding_iterator.advance 1"
| query_key :: query_tail, tree_key :: tree_tail, _ when
hkey_equal query_key tree_key ->
iterator#advance query_tail node tree_tail
| Variable :: query_tail, Parameter :: tree_tail, _
| Parameter :: query_tail, Variable :: tree_tail, _ ->
iterator#advance query_tail node tree_tail
| Variable :: query_tail, Symbol _ :: _, _
| Parameter :: query_tail, Symbol _ :: _, _ ->
let tree_fterm', skip =
skip_terms_fterm_partial tree_fterm 1
in
if skip = 0 then
iterator#advance query_tail node tree_fterm'
else
begin
match node.variant with
| DtInnerNode inner_node ->
iterator#descend_instance query_tail inner_node skip
| DtLeafNode _ ->
failwith "Discrimination_tree.get_shielding_iterator.advance 2"
end
| _ :: _, Variable :: tree_tail, _ ->
iterator#advance (skip_terms_fterm query_fterm 1) node tree_tail
| _ :: _, _ :: _, _ ->
()
| [], [], DtLeafNode leaf ->
iterator#save_leaf leaf
| Symbol _ as hkey :: query_tail, [], DtInnerNode table ->
begin
try
let node' =
Table.find table.next hkey
in
iterator#advance query_tail node' node'.prefix
with
| Not_found ->
()
end;
begin
try
let node' =
Table.find table.next Variable
in
iterator#save_node (skip_terms_fterm query_fterm 1) node' node'.prefix
with
| Not_found ->
()
end
| Variable :: query_tail, [], DtInnerNode table
| Parameter :: query_tail, [], DtInnerNode table ->
iterator#descend_instance query_tail table 1
| [], [], DtInnerNode _ ->
failwith "Discrimination_tree.get_shielding_iterator.advance 3"
| _, [], DtLeafNode _ ->
failwith "Discrimination_tree.get_shielding_iterator.advance 4"
method private descend_instance (query_tail: fterm) (table: 'data inner_node) (skip: int) : unit =
Table.iter
(fun hkey node ->
let skip' =
skip - 1 + (hkey_arity hkey)
in
let prefix, skip' =
skip_terms_fterm_partial node.prefix skip'
in
if skip' = 0 then
iterator#save_node query_tail node prefix
else
match node.variant with
| DtLeafNode _ ->
failwith "shielding_iterator.descend_instance"
| DtInnerNode table' ->
iterator#descend_instance query_tail table' skip'
)
table.next
end
method to_string : string =
tree_to_string _tree
end
class ['data] index
(__productivity: bool) (__data: 'data data)
=
object (_self)
inherit ['data] Term_indexing.index
__data
(new predicate_index __productivity)
end
let create_predicate_index (productivity: bool) (data: 'data data) : 'data Term_indexing.predicate_index =
new predicate_index productivity data
let create_index (productivity: bool) (data: 'data data) : 'data Term_indexing.index =
new index productivity data
class int_data =
object
method is_equal (x: int) (y: int) = x == y
method to_string x = string_of_int x
end
let create_int_index (productivity: bool) : int index =
new index productivity (new int_data)
class term_data =
object
method is_equal x y = Term.term_equal x y
method to_string x = Term.term_to_string x
end
let create_term_index (productivity: bool) : term index =
new index productivity (new term_data)
class literal_data =
object
method is_equal x y = Term.literal_equal x y
method to_string x = Term.literal_to_string x
end
let create_literal_index (productivity: bool) : literal index =
new index productivity (new literal_data)
class clause_data =
object
method is_equal x y = Term.clause_equal x y
method to_string x = Term.clause_to_string x
end
let create_clause_index (productivity: bool) : clause index =
new index productivity (new clause_data)
class literal_clause_data =
object
method is_equal (l1, c1) (l2, c2) =
Term.literal_equal l1 l2 && Term.clause_equal c1 c2
method to_string (l, c) =
Term.literal_to_string l ^ " : " ^ Term.clause_to_string c
end
let create_literal_clause_index (productivity: bool) : (literal * clause) index =
new index productivity (new literal_clause_data)