Skip to content
Rel
REL CONCEPTS
Installing Models

Installing Models

This concept guide introduces installed Rel models, which can be reused later in queries or as building blocks for other models.

Introduction

RAI databases are collections of:

  1. Relational data.
  2. Definitions and rules that define a model that operates on that data.

Simple definitions are often expressed as part of the query and forgotten afterwards. For example, the following query computes the sum of the numbers from 1 to 10, putting them in a myrange relation and then asking for sum[myrange]:

// query

def myrange(x) = range(1, 10, 1, x)
def output = sum[myrange]
Loading sum-of-the-numbers...

The relation myrange is a derived relation. When this code is issued as a query, it is not persisted in the database, and its definition is forgotten once the query is finished. This is convenient for simple auxiliary relations that are only used once.

For more advanced applications, you want to persist relation definitions in the database so they can be reused later in queries or as building blocks for more complex models. This step is called installing models. In this way, complex applications can be constructed in a modular way, as a collection of Rel libraries.

Installed Rel models are identified by a user-defined name. They can be added, removed, or updated, as you will see below.

Simple Example

Start by installing a small Rel model source that defines the transformation from Cartesian to spherical coordinates. You also define a relation π\pi, which holds the value of pi, taking advantage of Rel’s support for Unicode characters. This is a singleton relation, which means it has cardinality 1 and arity 1. Here’s what the code looks like:

// install

def π = pi_float64

@inline
def cartesian2spherical[R] = r, phi :
    r = sqrt[x^2 + y^2],
    phi = atan2[y, x] / π * 180
    from x, y where R(x, y)
🔎

The above code is meant to trigger an install_model RAI SDK API call. This is indicated by the “install” annotation above the code block.

In RAI Notebooks, installing models is done by an install cell.

The relation cartesian2spherical accepts an arity-2 relation R, which holds the Cartesian coordinate pairs (x, y), and evaluates a pair (r, phi), which is the radius and the angle of the corresponding 2D point. Now that you have installed this definition in the database, you can use it in a query like this:

// query

def xy = {("a", 2, 0); ("b", 0, 4); ("c", -9, 0); ("d", 1, -1)}
def r_phi[i] = cartesian2spherical[xy[i]]

def output = r_phi
Loading cartesian-to-spherical...

Installing Integrity Constraints

You can also install integrity constraints (ICs). The installed ICs will ensure that the database will always be in a state that fulfills the installed IC. For more information on ICs, see the Integrity Constraints concept guide.

For example, install an IC that makes sure that all of the elements of the myrel transaction are positive — along with an initial set of values for myrel itself:

// install

def myrel = {1; 2; 3}

ic myrel_positive(x) {
    myrel(x) implies x > 0
}

The integrity constraint passes, since everything in myrel is a positive number, and both the IC and the definition are successfully installed.

// query

myrel
Loading myrel...

Impact on Future Transactions

Installing Models

If you now try to extend the definition of myrel by installing another definition for myrel that also includes negative numbers, then the install attempt fails and the definition for myrel will not change:

// install

def myrel = {-1; 10}

def name = {"John"; "Jane"}

Any other definitions that you may have tried to install, such as name, will not succeed, and the installation of the entire code block will fail. Here’s how to check that myrel has not changed:

// query

myrel
Loading myrel-a...

Querying the Database

Query transactions that introduce definitions that violate installed ICs will fail. The system will let you know that the IC was violated, and no results are evaluated. The error message may contain the content of the requested relations and details of the IC violation. An exception is the RAI notebook; it evaluates the result, whether or not the IC fails. Here’s an example:

// query

def myrel = -1

def output = myrel

Base relation updates, which are queries that can modify the database state, will also fail if an IC is violated. The requested base relation change, via insert or delete, will not be persisted in the database.

To demonstrate this behavior, try to expand myrel again by adding -1, and create a new base relation called name_base_relation:

// update

def myrel = -1.0

def insert:name_base_relation = {"John"; "Jane"}
def output = name_base_relation

To check if the insertion was successful, query name_base_relation:

def output = name_base_relation

name_base_relation is still not defined, and the output is empty. The requested insertion into name_base_relation was not persisted in the database because of the IC violation.

ICs With Yet-To-Be Defined Relations

To install an integrity constraint that refers to a derived relation that has not yet been defined, you can assign the empty relation {} to it. This does not affect the values in the relation that might be assigned later because all definitions for the same relation form a union. Here’s an example:

// install

def my_data = {}

ic my_data_ic(x) {
    my_data(x) implies Int(x)
}

def my_data = {} ensures that my_data is defined, and no error message is issued.

RAI Notebooks

Installed models are marked as install cells in the RAI notebook. Install cells are given a unique system-generated ID by default. This ID can be replaced by a user-provided one. See the Guide to Working with RAI Notebooks for more details.

Normal query cells extract information transactions without changing the database transactions. Cells marked as update cells can change base relations, but they don’t install new sources. See the concept guide on Updating Data: Working with Base Relations for more details.

Model Introspection

Installed models are themselves stored in a base relation, which allows Rel programs to query and modify them.

This relation, available as rel:catalog:model, can be used to query, update, or delete the model sources themselves.

Here’s an example:

// update

def insert:rel:catalog:model["my-rel-model"] = """
	def myrange = range[1,100,1]
	"""
def output:stats = sum[myrange], max[myrange]
def insert[:foo] = myrange
def output:foo = foo <++ "undefined"
Loading catalog-update...

This code has inserted a definition for myrange and was able to query it in the very same transaction.

However, myrange was not yet available for updating the base relation foo, since insert and delete statements, unlike outputs, are evaluated at the start of the transaction, while outputs are evaluated at the end. See the Data Concept Guide for more details.

Here’s how to list the names of all the installed model sources, which include the Rel libraries:

// query

def output(name) = rel:catalog:model(name, _)
Loading model-sources...

In RAI notebooks, the names of the installed models in the notebook will have the following form: "notebooks/<notebook_name>/<install_cell_ID>".

To see the content of an installed model, you can query rel:catalog:model like this:

// query

def output = rel:catalog:model["my-rel-model"]
Loading rel-model...

This shows the code tagged "my-rel-model", which was installed above.

Here’s how to delete this model:

// update

def delete:rel:catalog:model["my-rel-model"] = rel:catalog:model["my-rel-model"]

You can similarly delete any of the other installed models.

See the RAI article on “Rel: Live Programming and Self-Modifying Models”, for more on the self-modifying aspects of Rel.