Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Indexing via discrimination tree #205

Merged
merged 57 commits into from
Nov 23, 2023
Merged
Show file tree
Hide file tree
Changes from 54 commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
d6d46e1
Typos
FissoreD Nov 8, 2023
d62f0a3
Start trie implementation
FissoreD Nov 9, 2023
8d41eb8
WIP
FissoreD Nov 13, 2023
0f84202
Oups
FissoreD Nov 13, 2023
1ca7bc2
Update DT
FissoreD Nov 13, 2023
d73f5c0
indentations
FissoreD Nov 13, 2023
4900ea4
discrimination tree jump to
FissoreD Nov 14, 2023
bb37a9c
Small correction
FissoreD Nov 14, 2023
cca8c09
small update
FissoreD Nov 14, 2023
26e0963
Add time stamp to clauses
FissoreD Nov 14, 2023
5b8ec2f
Take into account mode for filtering
FissoreD Nov 15, 2023
eb720fe
printf to spy
FissoreD Nov 15, 2023
b01864a
update changelog
FissoreD Nov 15, 2023
e35f26f
Error on invalid index arity (> arity of pred)
FissoreD Nov 15, 2023
6319f88
Update comment
FissoreD Nov 15, 2023
a0cd426
Minor updates
FissoreD Nov 15, 2023
4d0bfbe
Delete test.elpi
FissoreD Nov 15, 2023
02f96a7
WIP: deriving show for trie and disc tree
FissoreD Nov 15, 2023
3e359c4
Update Makefile
FissoreD Nov 15, 2023
ef2010a
Update show and pp of Disc tree
FissoreD Nov 15, 2023
d599620
remove print
FissoreD Nov 15, 2023
f084e23
Code format
FissoreD Nov 15, 2023
30997a9
Code format
FissoreD Nov 15, 2023
e96bd49
code cleanup
FissoreD Nov 15, 2023
c38e5ec
WIP
FissoreD Nov 16, 2023
e886272
Time stamp list rename
FissoreD Nov 16, 2023
5f92078
pp for Indexable term
FissoreD Nov 16, 2023
a1941dc
Update path generation from term for trie
FissoreD Nov 16, 2023
5b1042a
Pass more tests
FissoreD Nov 16, 2023
07183c7
Update Makefile
FissoreD Nov 18, 2023
be929a6
Update CHANGES.md
FissoreD Nov 18, 2023
a47ce20
Update src/compiler.ml
FissoreD Nov 18, 2023
359548a
Update src/data.ml
FissoreD Nov 18, 2023
e8e340d
Update src/data.ml
FissoreD Nov 18, 2023
739967a
`Other` constructor for non-variable element of path
FissoreD Nov 20, 2023
ed6b886
Aesthetic update
FissoreD Nov 20, 2023
4dd1c54
Add equal method to TimeStampList
FissoreD Nov 20, 2023
9e8d4af
Compare timestamps
FissoreD Nov 20, 2023
2b49894
specialize Trie/DT on data with timestamp list
gares Nov 21, 2023
be72175
wip
gares Nov 21, 2023
decdc99
wip
gares Nov 21, 2023
1a79b76
mutual recurs function for retrieval search
FissoreD Nov 22, 2023
04056b9
wip
gares Nov 22, 2023
f8f326a
wip
gares Nov 23, 2023
b3f821c
wip
gares Nov 23, 2023
6a4887d
wip
gares Nov 23, 2023
dda9916
wip
gares Nov 23, 2023
40a44a2
wip
gares Nov 23, 2023
2956db1
wip
gares Nov 23, 2023
356b4c2
wip
gares Nov 23, 2023
339a448
wip
gares Nov 23, 2023
8327441
doc
gares Nov 23, 2023
d1960f4
Arity of Cons is 0 when remaining depth is 0
FissoreD Nov 23, 2023
ee36bf9
readd typecheck on test-suite (now typeabbrv tests pass)
FissoreD Nov 23, 2023
a0f7d9e
Apply suggestions from code review
gares Nov 23, 2023
8713ff5
fix win ci
gares Nov 23, 2023
ffae80c
blind fix
gares Nov 23, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file added .ocamlformat
Empty file.
4 changes: 4 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
Library:
- New `std.fold-right`

Runtime:
- New clause retrieval through discrimination tree. This new index is enabled
whenever the `:index` directive selects only one argument with a depth `> 1`.

# v1.18.0 (October 2023)

Requires Menhir 20211230 and OCaml 4.08 or above.
Expand Down
20 changes: 16 additions & 4 deletions ELPI.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ trivial-facts :-
```

Side note: no solution is computed for goals like `_ = something`.
On the contrary a problem like `DummyNameUsedOnlyOnce = somthing` demands the
On the contrary a problem like `DummyNameUsedOnlyOnce = something` demands the
computation of the solution (even if it is not used), and hence can *fail* if
some variable occurring in something is out of scope for `DummyNameUsedOnlyOnce`.

Expand Down Expand Up @@ -308,8 +308,20 @@ If only one argument is indexed, and it is indexed at depth one, then Elpi uses
a standard indexing technique based on a perfect (for depth 1) search tree. This
means that no false positives are returned by the index.

If more than one argument is indexed, or if some argument is indexed at depth
greater than 1, then Elpi uses an index based on the idea of
### Discrimination tree index

If only one argument is indexed at depth greater than one, then Elpi uses
a [discrimination tree](https://www.cs.cmu.edu/~fp/courses/99-atp/lectures/lecture28.html).
Both the rule argument and the goal argument are
indexed up to the given depth. The indexing is not perfect, false positives may
be returned and ruled out by unification.

Indexed terms are linearized into paths. Paths are inserted into a trie data
structure sharing common prefixes.

### Hash based index

If more than one argument is indexed then Elpi uses an index based on the idea of
[unification hashes](http://blog.ndrix.com/2013/03/prolog-unification-hashes.html).

```prolog
Expand Down Expand Up @@ -618,7 +630,7 @@ syntax `{{:name` .. `}}` where `name` is any non-space or `\n` character.
Quotations are elaborated before run-time.

The [coq-elpi](https://github.com/LPCIC/coq-elpi) software embeds elpi
in Coq and provides a quatation for its terms. For example
in Coq and provides a quotation for its terms. For example
```prolog
{{ nat -> bool }}
```
Expand Down
4 changes: 2 additions & 2 deletions INCOMPATIBILITIES.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Known incompatibilities with Teyjus
===================================

This file tries to summarise known incompatibilities between Elpi and Teyjus.
This file tries to summarize known incompatibilities between Elpi and Teyjus.

# Semantics

Expand Down Expand Up @@ -37,7 +37,7 @@ This file tries to summarise known incompatibilities between Elpi and Teyjus.
- Module signatures are ignored.
- Elpi accumulates each file once; Teyjus does it multiple times, that is
always bad (all clauses are duplicated and tried multiple times, that is
rarely the expected behaviour).
rarely the expected behavior).
- Elpi understands relative paths as in `accumulate "../foo"`: resolution
of relative paths is done according to the path of the accumulating file
first or, if it fails, according to the TJPATH.
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ The elaborator manipulates terms with binders and holes
(unification variables) representing missing piece of
information. Some of them have to be filled in order
to make the term well typed. Some others are filled in because
the user has programmed the eleborator to do so, e.g. ad-hoc polymorphism.
the user has programmed the elaborator to do so, e.g. ad-hoc polymorphism.

Such software component is characterized by an high complexity
coming from the interplay of binders, reduction and unification,
Expand Down
22 changes: 11 additions & 11 deletions src/compiler.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1233,6 +1233,7 @@ let query_preterm_of_ast ~depth macros state (loc, t) =
Loc.show (snd (C.Map.find name map)) ^ ")")

let compile_mode (state, modes) { Ast.Mode.name; args; loc } =
let args = List.map to_mode args in
let state, mname = funct_of_ast state name in
check_duplicate_mode state mname (args,loc) modes;
state, C.Map.add mname (args,loc) modes
Expand Down Expand Up @@ -1356,7 +1357,7 @@ let query_preterm_of_ast ~depth macros state (loc, t) =
(state : State.t), lcs, active_macros,
{ Structured.types; type_abbrevs; modes; body; symbols }

and compile_body macros types type_abbrevs modes lcs defs state = function
and compile_body macros types type_abbrevs (modes : (mode * Loc.t) C.Map.t) lcs defs state = function
| [] -> lcs, state, types, type_abbrevs, modes, defs, []
| Locals (nlist, p) :: rest ->
let orig_varmap = get_varmap state in
Expand Down Expand Up @@ -1673,11 +1674,11 @@ module Spill : sig


val spill_clause :
State.t -> types:Structured.typ list C.Map.t -> modes:(constant -> bool list) ->
State.t -> types:Structured.typ list C.Map.t -> modes:(constant -> mode) ->
(preterm, 'a) Ast.Clause.t -> (preterm, 'a) Ast.Clause.t

val spill_chr :
State.t -> types:Structured.typ list C.Map.t -> modes:(constant -> bool list) ->
State.t -> types:Structured.typ list C.Map.t -> modes:(constant -> mode) ->
(constant list * prechr_rule list) -> (constant list * prechr_rule list)

(* Exported to compile the query *)
Expand Down Expand Up @@ -1727,7 +1728,7 @@ end = struct (* {{{ *)
| `Arrow(arity,_),_ ->
let missing = arity - nargs in
let output_suffix =
let rec aux = function false :: l -> 1 + aux l | _ -> 0 in
let rec aux = function Output :: l -> 1 + aux l | _ -> 0 in
aux (List.rev mode) in
if missing > output_suffix then
error ~loc Printf.(sprintf
Expand Down Expand Up @@ -2358,14 +2359,13 @@ let compile_clause modes initial_depth state
state, cl

let chose_indexing state predicate l =
let rec all_zero = function
| [] -> true
| 0 :: l -> all_zero l
| _ -> false in
let rec aux n = function
let all_zero = List.for_all ((=) 0) in
let rec aux argno = function
(* TODO: @FissoreD here we should raise an error if n > arity of the predicate? *)
| [] -> error ("Wrong indexing for " ^ Symbols.show state predicate)
| 0 :: l -> aux (n+1) l
| 1 :: l when all_zero l -> MapOn n
| 0 :: l -> aux (argno+1) l
| 1 :: l when all_zero l -> MapOn argno
| path_depth :: l when all_zero l -> Trie { argno ; path_depth }
| _ -> Hash l
in
aux 0 l
Expand Down
59 changes: 47 additions & 12 deletions src/data.ml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ module Constants : sig
module Set : Set.S with type elt = constant
val pp : Format.formatter -> t -> unit
val show : t -> string
val compare : t -> t -> int
end = struct

module Self = struct
Expand Down Expand Up @@ -115,6 +116,32 @@ let uvar_isnt_a_blocker { uid_private } = uid_private > 0 [@@inline];;
let uvar_set_blocker r = r.uid_private <- -(uvar_id r) [@@inline];;
let uvar_unset_blocker r = r.uid_private <- (uvar_id r) [@@inline];;

type arg_mode = Util.arg_mode = Input | Output [@@deriving show]

type clause = {
depth : int;
args : term list;
hyps : term list;
vars : int;
mode : mode; (* CACHE to avoid allocation in get_clauses *)
loc : Loc.t option; (* debug *)
}
and
mode = arg_mode list
[@@deriving show]

let to_mode = function true -> Input | false -> Output

(* Simpler pretty printer for clause *)
let pp_clause_simple (fmt:Format.formatter) (cl: clause) = Format.fprintf fmt "clause" (*
Format.fprintf fmt "[clause_args:";
pplist pp_term ", " fmt cl.args;
Format.fprintf fmt " ;; clause_hyps:";
pplist pp_term ", " fmt cl.hyps;
Format.fprintf fmt "]";*)
gares marked this conversation as resolved.
Show resolved Hide resolved

module DT = Discrimination_tree

type stuck_goal = {
mutable blockers : blockers;
kind : unification_def stuck_goal_kind;
Expand All @@ -138,25 +165,23 @@ and second_lvl_idx =
| TwoLevelIndex of {
mode : mode;
argno : int;
all_clauses : clause list; (* when the query is flexible *)
flex_arg_clauses : clause list; (* when the query is rigid but arg_id ha nothing *)
arg_idx : clause list Ptmap.t; (* when the query is rigid (includes in each binding flex_arg_clauses) *)
all_clauses : clause list; (* when the query is flexible *)
flex_arg_clauses : clause list; (* when the query is rigid but arg_id ha nothing *)
arg_idx : clause list Ptmap.t; (* when the query is rigid (includes in each binding flex_arg_clauses) *)
}
| BitHash of {
mode : mode;
args : int list;
time : int; (* time is used to recover the total order *)
time : int; (* time is used to recover the total order *)
args_idx : (clause * int) list Ptmap.t; (* clause, insertion time *)
}
and clause = {
depth : int;
args : term list;
hyps : term list;
vars : int;
mode : mode; (* CACHE to avoid allocation in get_clauses *)
loc : Loc.t option; (* debug *)
| IndexWithTrie of {
mode : mode;
argno : int; (* position of argument on which the trie is built *)
path_depth : int; (* depth bound at which the term is inspected *)
time : int; (* time is used to recover the total order *)
args_idx : clause DT.t;
}
and mode = bool list (* true=input, false=output *)
[@@deriving show]

type constraints = stuck_goal list
Expand All @@ -167,9 +192,19 @@ type suspended_goal = {
goal : int * term
}

(**
Used to index the parameters of a predicate P
- [MapOn N] -> N-th argument at depth 1 (head symbol only)
- [Hash L] -> L is the list of depths given by the urer for the parameters of
P. Indexing is done by hashing all the parameters with a non
zero depth and comparing it with the hashing of the parameters
of the query
- [IndexWithTrie N] -> N-th argument at arbitrary depth (TODO bound)
gares marked this conversation as resolved.
Show resolved Hide resolved
*)
type indexing =
| MapOn of int
| Hash of int list
| Trie of { argno : int; path_depth : int }
[@@deriving show]

let mkLam x = Lam x [@@inline]
Expand Down
Loading
Loading