# Probe a tensor expression

`sexpgpu probe [<file.sx>] --expr FORM` evaluates a small tensor expression with
the reference interpreter. The file supplies definitions and initialized models.
No loader, optimizer, training contract, GPU, or metric service is required.

## Arguments and output

| argument                   | behavior                                                                                                                                      |
| -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `<file.sx>`                | loads the file, then evaluates the expression in its environment; without one, the expression sees the prelude and a `require` adds a library |
| `--expr FORM`              | exactly one expression returning a tensor or multiple values of tensors                                                                       |
| `--variant V`, `--set k=v` | select the file's knobs before loading it                                                                                                     |
| `--json`                   | prints all tensor values in a structured document                                                                                             |
| `--max-elements N`         | caps the sum of intermediate and output tensor elements at `N`; default `100000`, positive integer                                            |

Text output is each tensor's shape, dtype, and first 64 row-major values,
written as that dtype writes them. JSON output is one line with every value:

```console
$ sexpgpu probe --expr '(iota [3] :dtype :i64)' --json
{"kind":"probe","device":"reference","outputs":[{"name":"output.0","shape":[3],"dtype":"i64","values":[0,1,2]}]}
```

Integers and booleans retain their JSON types. Nonfinite floats are the strings
`"NaN"`, `"Infinity"`, and `"-Infinity"`.

A relative `require` in the expression resolves beside the file, or against the
working directory without one. The expression sees the file's private and
imported bindings, including private functions used by imported macros; its own
definitions do not become file bindings. Nothing is read from standard input.

## Supported state and limits

The probe initializes the parameters and buffers of models bound at the file's
top level; a buffer initializer reads its parameters' starting values, as in a
run. Parameter paths and random initializer streams match ordinary compilation.
`defrun :seed` supplies the seed when present; the default is zero. A
parameterized model constructed inside the expression has no root and is
rejected. A parameter with `:load` or `with-loaded` requires a run.

The result must be tensors. `values` returns several tensors. Metrics, counters,
guards, and runtime context inputs are rejected. The probe does not apply the
run's precision policy, autodiff, or optimizer passes; explicit casts and
`gradient` execute as written.

The [evaluation work limit](https://sx.041.io/docs/lisp.md#evaluation-limits) covers the loaded file
and expression together. Before interpreting, the probe counts the elements of
every node of every used initializer and of the expression graph, unused
intermediates and the returned outputs included; `--max-elements` bounds that
count, not time: a matrix product does more work than its element count. Keep
probe dimensions small.

## Examples

`affine.sx` has a model and no training contract:

```lisp
(defknobs (width 3 "input width") (gain 2.0 "input value"))
(defmodel affine (&key (dim 3))
  (defparam weight (+ (cast (iota [dim]) :f32) 1.0))
  (defparam bias (full [dim] 0.5))
  (lambda (x) (+ (* x weight) bias)))
(defvar model (affine :dim width))
```

Its weight is `[1 2 3]` and its bias `[0.5 0.5 0.5]`:

```console
$ sexpgpu probe affine.sx --expr '(model (full [width] gain))'
output.0: [3] f32 [2.5, 4.5, 6.5]
$ sexpgpu probe affine.sx --set width=4 --expr '(model (ones [width]))' --json
```

A library function and a derivative can also be checked without a file:

```console
$ sexpgpu probe --expr '(progn (require "sexpgpu/nn" rms-norm) (rms-norm (full [2 3] 2.0) :eps 0.0))' --json
$ sexpgpu probe --expr '(let* ((x (cast (iota [3]) :f32)) (y (sum (* x x)))) (values y (gradient y x)))'
output.0: [] f32 [5.0]
output.1: [3] f32 [0.0, 2.0, 4.0]
```

Diagnostics use the [standard codes](https://sx.041.io/docs/errors.md). `--json` emits the same
diagnostic array as `check --json`, and failures exit with code 1.

---

SexpGPU documentation. Every page: https://sx.041.io/llms.txt
