View on GitHub

ascent

logic programming in Rust

BYODS is an extension of Ascent that allows custom data structures backing relations. The OOPSLA paper Bring Your Own Data Structures to Datalog describes the semantics and high-level design of BYODS, and presents a number of experiments demonstrating the capabilities of BYODS.

With BYODS, any relation in an Ascent program can be tagged with a data structure provider:

ascent! {
    #[ds(rels_ascent::eqrel)]
    relation rel(u32, u32);
    // ...
}

In the above example, relation rel is backed by the eqrel data structure provider, which makes rel an equivalence relation.

In the above example, rels_ascent::eqrel is the path of the module containing the macros required of a data structure provider. You can define your own data structure providers. To see what macros are required of a data structure provider, see ascent::rel, which is the default data structure provider.

The most important macros of a data structure privider are rel_ind and rel_ind_common.

Macro invocations for rel_ind_common and other macros look like this:

my_provider::rel_ind_common!(
  rel,          // rel name 
  (u32, u32),   // column types
  [[1]],        // logical indices
  ser,          // parallel (par) or serial (ser)
  (),           // user-specified params
)

These macro invocations evaluate to types that implement certain traits. rel_ind! returned types must implement ToRelIndex. This trait provides an indirection, allowing relation indices to share data (the type returned by rel_ind_common!). The type returned by the to_rel_index function of this trait is used to read the relation data, and must implement RelIndexRead and RelIndexReadAll traits. The type returned by to_rel_index_write is used to write new values to an index, and must implement RelIndexWrite and RelIndexMerge.

These traits have Key and Value associated types. Key is the tuple of the indexed-on columns, and Value is the tuple of the remaining columns. For example, for an index [1, 2] of a relation relation rel(Col0, Col1, Col2), the Key type would be (Col1, Col2) and the Value type would be (Col0,). For RelIndexReadAll, the Key and Value types are references to tuples, or tuples of references (see TupleOfBorrowed). The same is true for the Value type of RelIndexRead.

rel_ind_common! provides sharing of data between indices of a relation. Types returned by this macro invocation only need to implement RelIndexMerge.

To support parallel Ascent, relation indices need to implement parallel versions of the above traits. For example, CRelIndexRead, CRelIndexReadAll, and CRelIndexWrite.

TODO: finish the guide