Skip to main content

README.md

# ShotTo

**ShotTo** is an Elixir implementation of NCPO-LNF — the βη-long-normal
Computability Path Order of Niederhauser and Middeldorp, _NCPO goes
Beta-Eta-Long Normal Form_ (2025) — for ordering terms of Church's simple
type theory as represented by the [`shot_ds`](https://hexdocs.pm/shot_ds/)
library.

`ShotTo` is developed at the [University of Bamberg](https://www.uni-bamberg.de/en/),
[Chair for AI Systems Engineering](https://www.uni-bamberg.de/en/aise/),
primarily as an orientation order for a higher-order tableau prover.

## What it does

Given two terms _s_ and _t_ in βη-long normal form and a choice of
_ordering parameters_, `ShotTo` decides the boolean predicate
$s >^1_\tau t$ of Definition 8 of the paper. It is a drop-in decision
procedure rather than an SMT-constraint generator: the parameters
(precedences, statuses, accessibility, basicness) are fixed inputs
supplied by the caller, not unknowns.

```elixir
import ShotDs.Hol.Dsl
import ShotDs.Hol.Definitions
alias ShotDs.Stt.TermFactory, as: TF
alias ShotTo.Parameters

params = Parameters.new(const_precedence: %{"f" => 1, "c" => 0})
f  = TF.make_const_term("f", Type.new(:i, :i))
c  = TF.make_const_term("c", type_i())
fc = app(f, c)

ShotTo.gt?(fc, c, params)       # => true   (by ⟨F▷⟩: c is a subterm of f(c))
ShotTo.gt?(c, fc, params)       # => false
ShotTo.compare(fc, c, params)   # => :greater
```

## API surface

### `ShotTo`

- `gt?(s_id, t_id, params \\ default)` — decides $s >^1_\tau t$.
- `geq?(s_id, t_id, params \\ default)` — reflexive closure.
- `compare(s_id, t_id, params \\ default)` — returns `:greater`,
  `:less`, `:equal`, or `:incomparable`.

### `ShotTo.Parameters`

A struct with fields

- `sort_precedence` — map or function on atoms giving the rank of each
  base sort (higher is greater in $\succ_{\mathcal{S}}$).
- `const_precedence` — map or function on constant identifiers giving
  the rank in $\succ_{\mathcal{F}}$.
- `status` — map or function assigning `:lex` or `:mul` to each
  constant.
- `basic_sorts``:all`, a MapSet, or a predicate.
- `accessible``:all`, a MapSet of `{name, index}` pairs, or a binary
  predicate.

Helpers:

- `Parameters.new/1`, `Parameters.from_precedence_list/2`, and lookup
  functions `prec/2`, `sort_prec/2`, `status/2`, `basic?/2`,
  `accessible?/3`, `equiv?/3`, `gt?/3`.
- `Parameters.validate/2` for a best-effort sanity-check against a map
  of constant types.

Defaults are permissive: all sorts equivalent and basic, all positions
accessible, all constants equivalent with `:lex` status. Under these
defaults NCPO-LNF reduces to the simple subterm order plus
lexicographic-in-the-same-head comparison, which is rarely what you
want; at a minimum supply a `const_precedence`.

## Status and caveats

- NCPO-LNF is not (yet known to be) **transitive**. Use `ShotTo` to
  decide orientation of one pair at a time, not as a comparator for
  sorting or for building total orders on sets of terms.
- `ShotTo.Parameters.validate/2` is a best-effort check of the
  accessibility and basicness conditions (Definition 5 of the paper). A
  sound but conservative choice is to leave `accessible: :all` and
  `basic_sorts: :all` — the conditions then hold vacuously.
- Every lambda opening allocates a fresh ShotDs free variable. Callers
  concerned with global ETS growth should wrap their comparisons in
  `ShotDs.Stt.TermFactory.with_scratchpad!/1`; fresh variables
  generated during the comparison will then die with the scratchpad.

## Installation

Add `shot_to` to your dependencies:

```elixir
def deps do
  [
    {:shot_to, "~> 0.1"}
  ]
end
```

## License

MIT.