aboutsummaryrefslogtreecommitdiffstats
path: root/docs/modes.org
diff options
context:
space:
mode:
authorMarcos Magueta <maguetamarcos@gmail.com>2026-10-31 02:30:40 -0300
committerMarcos Magueta <maguetamarcos@gmail.com>2026-10-31 02:30:40 -0300
commit55dd8ebfdd2629f97388e52953fe5bbd52733745 (patch)
tree8f8d607c6cfa73f1de24d0dde3ef39b42752b577 /docs/modes.org
parent71856adc5ff5d64c7be1b37854fc8a205d55e482 (diff)
downloadRNT-55dd8ebfdd2629f97388e52953fe5bbd52733745.tar.gz
RNT-55dd8ebfdd2629f97388e52953fe5bbd52733745.zip
update docs with partial bindings
Diffstat (limited to 'docs/modes.org')
-rw-r--r--docs/modes.org67
1 files changed, 42 insertions, 25 deletions
diff --git a/docs/modes.org b/docs/modes.org
index 2337b29..1cd5905 100644
--- a/docs/modes.org
+++ b/docs/modes.org
@@ -70,14 +70,21 @@ The principle above is wider than what RNT can do today. The
- =contains= answers with every attribute bound, so it realizes the
modes whose =bound= is every attribute.
-No operation produces the tuples that agree with a partial binding. A
-relation may declare a mode such as ={title; Finite}=, and
-=Mode.generation= takes it into account, but nothing in RNT can act on
-it. In particular, a relation cannot decide membership through a mode
-with a partial binding. It decides only by its own test, or by
-enumerating with nothing bound. A partial mode becomes usable once
-there is an operation that produces tuples under a binding, which is
-also what [[*Indexes][indexes]] need.
+Neither produces the tuples that agree with a partial binding, and RNT
+does not ask every relation for them. A binding is a condition on
+tuples, and conditions belong to a query language, as [[file:partial-bindings.org::*Where a binding belongs][partial bindings]]
+explains. Two pieces reach partial bindings instead.
+
+- A substantial relation offers =lookup= through the [[file:../lib/protocols/Indexed.mli][Indexed]] protocol,
+ the tuples whose attribute =a= holds a given value, read from its
+ index on =a=. That realizes its mode ={a; Finite}=.
+- A FOL =Where= restricts a plan to the tuples that agree with a
+ binding, and reads an index when its input offers one, as [[*Modes of a FOL plan][the modes
+ of a FOL plan]] describe.
+
+A mode with a partial =bound= that neither reaches is still declared and
+unused. A relation still decides membership only by its own test, or by
+enumerating with nothing bound.
* How contains decides
A substantial relation looks the tuple up by its hash.
@@ -104,9 +111,10 @@ evaluator gave it whatever test it could.
* What relations declare
A substantial relation stores its tuples in a set keyed by the hash of
-each whole tuple. It declares ={∅; Finite}= for enumerating that set,
-and ={all; Bounded 1}= for the lookup by hash, which needs every
-attribute to compute the hash.
+each whole tuple, and keeps an [[*Indexes][index]] on each attribute. It declares
+={∅; Finite}= for enumerating that set, ={all; Bounded 1}= for the lookup
+by hash, which needs every attribute to compute the hash, and
+={a; Finite}= for the index on each attribute =a=.
An ephemeral relation that =EphemeralRelation.literal= builds from =n=
tuples declares ={∅; Bounded n}=.
@@ -127,23 +135,34 @@ executes anything, and records them on each relation it derives.
- =Base r= has the modes of =r=.
- =Project (p, A)= keeps the modes of =p= whose =bound= lies within
=A=, with the same =yields=.
+- =Where (Base r, b)=, when =r= offers an index on an attribute =b=
+ binds, has the modes of =r= with the attributes of =b= taken out of
+ each =bound=, by =Mode.given=. The binding supplies their values, and
+ the index produces the tuples, so ={a; Finite}= becomes ={∅; Finite}=.
+- Any other =Where (p, b)= keeps the modes of =p=, since it can only
+ filter what =p= enumerates.
A projection never yields more tuples than its input, so =yields=
carries over. A mode that needs an attribute outside =A= no longer
-applies, because a tuple of the projection holds no value for it.
+applies, because a tuple of the projection holds no value for it. A
+restriction never yields more tuples than its input either.
Take =book(title, author)= as a substantial relation, projected on
=title=. Asking whether ={title: "Codd"}= belongs to the projection
asks whether some book has that title, by any author. The lookup by
-hash needs the author to hash the whole tuple, so the projection keeps
-only ={∅; Finite}=.
+hash needs the author to hash the whole tuple, so the projection loses
+it, and keeps ={∅; Finite}= and the mode ={title; Finite}= of the index
+on =title=.
FOL gives a membership test only where it has one. The relation it
derives for =Base r= takes the =contains= of =r= as its test, so FOL
over a substantial relation still looks tuples up by hash. The relation
it derives for a projection has no test, so its =contains= enumerates
the projection, which reads all of =book=, and compares. That ends
-because =book= is finite.
+because =book= is finite. Asking the same question as
+=Where (Project (book, title), {title: "Codd"})= reads only the index
+entries for ="Codd"=, since FOL pushes the restriction below the
+projection when the projection keeps every attribute it binds.
A projection of a =Countable= relation stays =Countable=. FOL still
streams it, since a projection reads one tuple at a time and never
@@ -151,14 +170,11 @@ needs the end. Asking such a projection whether it holds a tuple fails
with =undecidable-membership=.
* Indexes
-An index on an attribute =a= would be a tree keyed by the value of =a=
-and the hash of the tuple, and would add the mode ={a; Finite}=. A
-projection that keeps =a= keeps that mode, so with one index per
-attribute every membership question could stay a lookup. That takes two
-things RNT does not have, the index trees and an operation that
-produces tuples under a partial binding, as [[*Reachable bindings][reachable bindings]]
-explains. Without the operation, the mode an index adds would be
-declared and never used.
+A substantial relation keeps an index on each attribute =a=, a tree
+keyed by the encoded value of =a= and the hash of the tuple, and each
+adds the mode ={a; Finite}=. A projection that keeps =a= keeps that mode,
+and a FOL =Where= that binds =a= reads only the matching entries.
+[[file:partial-bindings.org][Partial bindings]] describes how the indexes are stored, read and built.
Modes carry no cost. A lookup and a full scan both appear as an
exhaustible generation, and choosing between them belongs to whatever
@@ -167,5 +183,6 @@ plans the query.
* Where exhaustion matters
Only a reader that runs a relation to its end needs it exhaustible.
=Relation.read= drains a relation, and admission drains every [[file:denial.org][denial]]
-that holds a tuple, so both hang on a =Countable= relation. Neither
-checks modes yet. Denials will check them once they are reworked.
+that holds a tuple, so both hang on a =Countable= relation. Admission
+asks a denial for its modes first and refuses one that does not end.
+=Relation.read= does not check them yet.