# Scallop Context

The most fundamental point of interaction of `scallopy`

is `ScallopContext`

.
The following is a very simple example setting up a `ScallopContext`

to compute the `edge-path`

program:

```
import scallopy
# Creating a new context
ctx = scallopy.ScallopContext()
# Add relation of `edge`
ctx.add_relation("edge", (int, int))
ctx.add_facts("edge", [(0, 1), (1, 2)])
# Add rule of `path`
ctx.add_rule("path(a, c) = edge(a, c) or path(a, b) and edge(b, c)")
# Run!
ctx.run()
# Check the result!
print(list(ctx.relation("path"))) # [(0, 1), (0, 2), (1, 2)]
```

Roughly, the program above can be divided into three phases:

- Setup the context: this involves defining relations, adding facts to relations, and adding rules that do the computation
- Running the program inside of context
- Fetch the results

While the 2nd and 3rd steps are the place where the computation really happens, it's more important for the programmers to correctly setup the full context for computation. We now elaborate on what are the high-level things to do when setting up the context

## Configurations

When creating a new `ScallopContext`

, one should configure it with intended provenance.
If no argument is supplied, as shown in the above example, the context will be initialized with the default provenance, `unit`

, which resembles untagged semantics (a.k.a. discrete Datalog).
To explicitly specify this, you can do

```
ctx = scallopy.ScallopContext(provenance="unit")
```

Of course, Scallop can be used to perform reasoning on probabilistic and differentiable inputs. For instance, you can write the following

```
ctx = scallopy.ScallopContext(provenance="minmaxprob") # Probabilistic
# or
ctx = scallopy.ScallopContext(provenance="diffminmaxprob") # Differentiable
```

For more information on possible provenance information, please refer to the provenance section.
It it worth noting that some provenance, such as `topkproofs`

, accept additional parameters such as `k`

.
In this case, you can supply this as additional arguments when creating the context:

```
ctx = scallopy.ScallopContext(provenance="topkproofs", k=5) # top-k-proofs provenance with k = 5
```

## Adding Program

Given that a context has been configured and initialized, we can set it up the quickest by loading a program into the context.
One can either load an external `.scl`

file, or directly inserting a program written as Python string.
To directly add a full program string to the context, one can do

```
ctx.add_program("""
rel edge = {(0, 1), (1, 2)}
rel path(a, c) = edge(a, c) or path(a, b) and edge(b, c)
""")
```

On the other hand, assuming that there is a file `edge_path.scl`

that contains the same content as the above string, one can do

```
ctx.import_file("edge_path.scl")
```

## Adding Relations

Instead of adding program as a whole, one can also add relations one-at-a-time.
When adding new relations, one would need to supply the name as well as the type of the relation.
For example, the `edge`

relation can be defined as follows

```
ctx.add_relation("edge", (int, int))
```

Here, we are saying that `edge`

is an arity-2 relation storing pairs of integers.
Note that we are specifying the type using Python's `int`

type.
This is equivalent to the `i32`

type inside Scallop.
Therefore, the above instruction tranlates to the following Scallop code:

```
rel edge(i32, i32)
```

Many existing Python types can directly translate to Scallop type. In particular, we have the mapping listed as follows:

Python Type | Scallop Type |
---|---|

`int` | `i32` |

`bool` | `bool` |

`float` | `f32` |

`str` | `String` |

In case one want to use types other than the listed ones (e.g., `usize`

), they can be accessed directly using the string `"usize"`

, or they can be accessed through predefined types such as `scallopy.usize`

.
The example below defines a relation of type `(usize, f64, i32)`

:

```
ctx.add_relation("my_relation", (scallopy.usize, "f64", int))
```

Specifically for arity-1 relations, users don't need to use a tuple to specify the type. For instance,

```
ctx.add_relation("digit", int)
```

## Adding Facts

The most basic version of adding facts into an existing relation inside of an existing context.
We are assuming that the context has a provenance of `"unit"`

.

```
ctx.add_facts("edge", [(1, 2), (2, 3)])
```

If the relation is declared to be having arity-1 and that the type is a singleton type instead of a 1-tuple, then the facts inside of the list do not need to be a tuple.

```
ctx.add_relation("digit", int)
ctx.add_facts("digit", [1, 2, 3])
```

### Probabilistic Facts (Tagged Facts)

When the Scallop context is configured to use a provenance other than.
If one wants to add facts along with probabilities, they can wrap their non-probabilistic facts into tuples whose first element is a simple probability.
For example, if originally we have a fact `1`

, wrapping it with a corresponding probability gives us `(0.1, 1)`

, where `0.1`

is the probability.

```
ctx.add_facts("digit", [1, 2, 3]) # without probability
ctx.add_facts("digit", [(0.1, 1), (0.2, 2), (0.7, 3)]) # with probability
```

Of course, if the original facts are tuples, the ones with probability will be required to wrap further:

```
ctx.add_facts("color", [("A", "blue"), ("A", "green"), ...]) # without probability
ctx.add_facts("color", [(0.1, ("A", "blue")), (0.2, ("A", "green")), ...]) # with probability
```

We can extend this syntax into tagged facts in general.
Suppose we are using the boolean semiring (`boolean`

), we are going to tag each fact using values such as `True`

or `False`

.

```
ctx = scallopy.Context(provenance="boolean")
ctx.add_relation("edge", (int, int))
ctx.add_facts("edge", [(True, (1, 2)), (False, (2, 3))])
```

### Non-tagged Facts in Tagged Context

## Adding Rules

### Tagged Rules

## Running

## Additional Features

There are more features provided by the `ScallopContext`

interface.
We hereby list them for reference.

### Cloning

One can copy a context to create a new context. The resulting context will contain all the program, configurations, and provenance information.

```
new_ctx = ctx.clone()
```

The cloning feature relates to pseudo-incremental computation and branching computation. We elaborate on this in the Branching Computation section.

### Compiling

### Iteration Count Limit

One can configure the

### Early Discarding

### Obtaining Context Information

### Foreign Functions and Predicates

### Saving and Loading

Please refer to the Saving and Loading section for more information.