# `Dmn.Run`
[🔗](https://github.com/FeeJai/BDM/blob/dmn-v0.1.0/apps/dmn/lib/dmn/run.ex#L1)

Runs a compiled model.

The units that the decisions asked for need are run in the order of the plan (`Dmn.Compiled.plan/2`), each once: a unit gets the
values of the units it reads as the bindings of its prepared expression, and gives its value to the units that read it. Nothing is
parsed, resolved or typed here.

## The inputs

The inputs are a map of the names of the input data to their values (or `{namespace, name}`, for the input data of a model that is
imported), which are FEEL values (`Feel.Value`): numbers are `Decimal`s,
contexts are maps. An input that is not given is `null`. A value that does not fit the declared type or the allowed values of its
input data is converted, or is `null` with an error, in every unit that reads it, as the declarations of FEEL say (D-138).

## Errors

An error of an element (a type mismatch, a division by zero, a table that is broken) makes its value `null` and is a
diagnostic, and the run goes on: DMN 1.6, 7.3.8, calls this `:lenient`. With `mode: :strict` the first error ends the run, and the
result is `{:error, %Dmn.Error{kind: :run, code: :strict}}` with the diagnostic in its details. An element that could not be compiled
(a text that does not parse, a cycle) is `null` with its errors, in both.

What is wrong with an element whatever the data (a requirement that names nothing, a name or an id that another element has, a type
it declares that is not defined) is a fault of its unit: every run of a model that needs the element says it as a diagnostic, and a
strict run ends on it. A run does not look at the elements it does not need, and does not say that a model is valid: that is
`Dmn.validate/1`.

## Recursion

The units of a recursion group (`Dmn.Compiled.groups`, `Dmn.compile/2` with `recursion: true`) are run with links to the members they
read instead of their values (`Feel.Recursion`): each is run when the plan reaches it, the links are made once for the group,
and a call through one is a call of FEEL in the run it is made in, so `Feel.Limits` ends a recursion that does not end.

## Options

`:mode` (`:lenient` or `:strict`), and, for the runs of FEEL, `:clock`, `:entropy`, `:limits` (`Feel.Limits`). A run keeps to the
limits that the model was compiled with (`:feel_limits` of `Dmn.compile/2`) unless it is given `:limits`, which take their place.
Only these keys and `:mode` are accepted by this internal execution module. Mode defaults to `:lenient`.
The public `Dmn.evaluate/4`, `Dmn.evaluate_all/4`, `Dmn.run/2` and `Dmn.invoke/4` wrappers validate and consume
`:sandbox` and `:guard`, then apply the shared `Feel.Worker` boundary. Calling this module directly
does not start a worker. Unknown keys, repeated keys, malformed keyword lists and invalid modes
return a run error with code `:invalid_options`.

# `evaluate`

```elixir
@spec evaluate(Dmn.Compiled.t(), [String.t()], map(), keyword()) ::
  {:ok, Dmn.Result.t()} | {:error, Dmn.Error.t()}
```

Runs the decisions called `names`, with the inputs.

Returns the `Dmn.Result`, or an error of the kind `:run`: a name that is not a decision, a business knowledge model or a decision
service of the model (a string, that is: anything else is none), or one that more than one element has (`:unknown_decision`,
`:ambiguous_name`), names that are not a list, inputs that are not a map, or options that are not what they should be
(`:invalid_inputs`, `:invalid_options`), or a run that ended in strict mode. Nothing raises for what the arguments are (DD-36), whether
a caller built them or got them from outside.

# `invoke`

```elixir
@spec invoke(Dmn.Compiled.t(), String.t(), map() | list(), keyword()) ::
  {:ok, Dmn.Result.t()} | {:error, Dmn.Error.t()}
```

Calls a business knowledge model or a decision service of the model, as a function (DMN 1.6, 10.4): the arguments are a map of the
names of the parameters to values, or a list of values in the order of the parameters.

A map may have names that are not parameters (the inputs of a test, say): they are left out. The function value is made by running
the elements it needs, as for a decision, and the call is a call of FEEL, so the arguments are converted to the types of the
parameters, a missing argument is `null`, and the depth of calls is limited. Returns the `Dmn.Result` (with the value of the call
under `name`).

Nothing raises for the model or the arguments: an element that is not a function (a decision, a business knowledge model that has
no logic, or an external one that cannot be run) is an error `:not_a_function`, a name that is not a string is `:unknown_decision`, and
arguments that are neither a map of names nor a list are `:invalid_arguments`.

An error of the call is the code of the error of FEEL (`:limit_exceeded` for a limit of `Feel.Limits`, as a decision that passes it
has), or `:feel_error` where it has none, with `details.kind` the kind of it; `:strict` is that of an error in the `:strict` mode (DD-36).

---

*Consult [api-reference.md](api-reference.md) for complete listing*
