---
# System prepended metadata

title: GTScript execution model (Accessor view)
tags: [GTScript]

---

# GTScript execution model (Accessor view)

###### tags: `GTScript`

## Definitions

* **Field**: a function from point to value. Usally represents arrays. For the practical usage it is imporant that any field can be exposed to C++ as a model of [SID concept](https://github.com/GridTools/gridtools/blob/master/include/gridtools/sid/concept.hpp). 
* **Value** (or **ValueType**): a type of the field element.
* **Column**: a type that represents a vertical column within the field. Column has a size that is a vertical size of compute domain. The sizes of all columns within a stencil are the same. 
* **Value accessor**: a functor that takes offsets and returns a value. 
* **Column accessor**: a functor that takes offsets and returns a column. Vertical offset is interpreted as a cycling. I.e. if `acc() == [1, 2, 3]`, it is expected that `acc(k=-1) == [3, 1, 2]` 
* **Polymorphic function**: a function with two overloads. The first overload takes values and returns a value (or a tuple of values). The second overload takes columns and returns a column (or a tuple of columns). Semantically the column oveload just calls value overload element wise.
* **Polymorphic stencil**: a function with two overloads. The first overload takes value accessors and returns a value (or a tuple of values). The second overload takes column accessors and returns a colum (or a tuple of columns). Overload sematics should be consistent.
* **Stencil**: a function that takes column accessors and returns a column (or a tuple of columns). Polymorphic stencil is a stencil as well. 
* **Grid**: a set of points.
* **Compute domain**: a subset of a grid.
* **Fencil**: one or more pairs of a stencil closures (stencils with bound input and output fields) with associated compute domains.
* **ScanPass**: a function that takes a value and value accessors and returns a value (or a tuple of values). It represents the body of the vertical loop with the vertical dependencies between the layers. The first argument is what the pass returned processing the previous layer. 

## Grammar

* **Program** consists of function definitions and fencil definitions. 
* **Fencil definition** serves as an entry point. I.e. it is an entity to execute.
* **Function definition** consists of the name, argument list and a single expression that represents the body.
* Expressions:
  - **value literal**
  - **offsets literal**: It is important that offsets are literals for extent analysis reasons.
  - **symbol**: the name of an arg or a function
  - **function call**: the name and the args as an expression list.
 optional:
  -  **let**: as it is known in the functional languages.

## Builtin functions

* All arithmetic operations, comparisons, etc. are represented in the form of polymorphic functions.
* Condition construct is repesented in the form of polymorphic fuction as well: `if_(cond, lhs, rhs)`.
* **lift** : a function from a stencil to a function that returns an accessor (or a tuple of accessors, if the input function returns tuple). If lift is applied to polymorphic stencil, the result has two overloads. The first oveload takes value accessors and returns value accessor (or a tuple of value accessors), the second overload takes column accessors and returns column accessor (or a tuple of column accessors). lift represents temporary creation of function inlining. Here is a python snippet that describes lift semantics:
```python=
def lift(stencil):
    def res(*fs):
        def res(**outer_offsets):
            def wrapper(f):
                def res(**offsets):
                    for dim in outer_offsets:
                        if not dim in offsets:
                            offsets[dim] = 0
                        offsets[dim] += outer_offsets[dim]
                    return f(**offsets)
                return res
            return stencil(*(wrapper(f) for f in fs))
        return res
    return res
```
 
* **scan**: a function with the signature:
  ```python
  scan(scan_pass: ScanPass, is_forward: bool, init) -> Stencil
  ```
  It returns a stencil that executes a vertical loop. `scan_pass` serves as a body of the loop; `is_forward` defines direction. The values that `scan_pass` returns are written to the returning column and also passed to the next invocation of `scan_pass` as a first parameter. On the first invocation `init` value is passed to `scan_pass`. Note that scan returns a `Stencil` but not a `Polymorhpic stencil`
* tuple constructor
* tuple accessor
  
## No explicit vertical and horizontal intervals in stencils

Boundary conditions are solved by passing a mask field.

```python=
def baz(pos_mask, inp):
    return if_(on_left_boder(pos_mask), foo(inp), bar(inp)) 
```

## How to use this execution model

The defintions above form an intermediate language. Let's call it Bob (semantics intermediate language). Suppose we modified Gt4Py so that any IR chain goes through the Bob.

Let us implement naive lowering from Bob. It serves as a reference point for other backends validation.

SIR serves as a border line between backends and frontends. We can split all Gt2Py development tasks in catergories:
1. Frontend only -- Bob and backend IRs remain unchanged.
2. Backend only -- Bob and frontend IRs remain unchanged.
3. Extension -- new feature in Bob; new feature in backends and frontends. 
4. Global -- we have to touch all IRs in the pipeline.

The forth category is hard. Specially for the team development. The third is better. We can split it into stages -- first do additions in Bob and backends; second do backends. 
By desiging the Bob right we can minimize the number of tasks in the forth and the third category. 


## Important features

* Any legit (without racing problems) script that is written in the current Gt4Py can be expressed in Bob. The main obstacle in this exercice are inout paramters. Inout temporaries are solved by adding yet another temporary. The pattern for processing external inout parameters is the following: `foo(a:inout)` is transformed to `new_foo(a:in, aa:out)`. At the end we will end up with the fencil that contains a stencil closure with some field that is included both in input and output paramters. 
* Composability. Many possible forntend constructs can be expressed in Bob. Also because of composability some optimizations can be solved as Bob -> Bob transformations. 
* It is easy to fully define semantics of Bob.
* Naive implementation is straightforward.
* k-caches, temporaries, extents and all we can currently analyse is posible to do from Bob input 
* SIR grammar is small; most things go into builins; most extensions will be in the form of builtins. This is handy for backend IRs. 


## Prior Art

* [GTScript2 proposal (Anton)](https://hackmd.io/lJzO4Og7TSiqCup8ZEiicA)
* [The task definiton as it is in the betting table](https://hackmd.io/63Oqw0OtToWI-5vG4kBORw)
* [The notes from discussion at 10.03.21](https://hackmd.io/LUU7i-zMTLmNEWm-Yh9LMQ)
* [Vertical computations with columns (Felix)](https://hackmd.io/n8yvkv7iQPSCHqezOK85dg)
* [Formal Semantics for the Parallel Model (Felix)](https://hackmd.io/_y9GsdxrQa-DmwwcHDHx2g)
* [Evaluation of vertical stencil ideas (Anton)](https://hackmd.io/_y9fjAMmTkqNdIv10xbAbg)
* [Ideas on vertical loops python syntax (Felix)](https://hackmd.io/vLCJefsOQH6845z6WVKopA)