Qu

input

Builtin index · Statistics & ML

result = input(n)

Input: n · Output: result

What it is

Starts the pipeline sugar: n (a positive integer) is the number of input features.

Overloads

One call shape — this function is not overloaded.

CodeInputOutputDescription
result = input(n)
n numbernot documented yet
result Record
Returns a pipeline_input Record tracking the running output width and an (initially empty) layer list, ready to be piped into dense(...) stages and finished with compile(...).

Examples

From the documentation, and run by the build -- the output and the figure below are what the engine actually produced. Simplest first.

spec = input(3)
print(spec.out_dim)          # 3 -- nothing built yet

print(spec.layers)           # () -- empty


net = input(3) |> dense(5, activation="relu") |> dense(1)
print(net.out_dim)            # 1 -- the last layer's output size

print(length(net.layers))     # 2 -- one record per dense() stage

output
3
()
1
2

from collections-strings

x = [1.0, 2.0, 3.0, 4.0]
y_true = [2.0, 4.0, 6.0, 8.0]
w = param(0.0)
function loss_fn(w)
    pred = w * x
    diff = pred - y_true
    return mean(diff .^ 2)
end function
opt = sgd(w, 0.01)
losses = train_loop("loss_fn", w, 100, optimizer = "opt")
print("train_loop (sgd): loss {round(losses[0], 3)} -> {round(losses[99], 5)}")
tape_reset()

w2v = 0.0
opt2 = adam(param(w2v), lr = 0.1)
for t = 0 to 19
    tape_reset()
    w2 = param(w2v)
    pred = w2 * x
    loss2 = mean((pred - y_true) .^ 2)
    g = grad(loss2, wrt = w2)
    opt2 = optimizer_step(opt2, g)
    w2v = opt2._params[0]
end for
print("optimizer_step (adam): w -> {round(w2v, 4)} (target 2.0)")
tape_reset()

# One step each from w=1.0, grad=3.0 -- same optimizer_step(opt, grad) call.

w3 = param(1.0)
grad3 = [3.0]
r1 = optimizer_step(nesterov_sgd(w3, lr = 0.05, momentum = 0.9), grad3)
r2 = optimizer_step(adamw(w3, lr = 0.05), grad3)
r3 = optimizer_step(nadam(w3, lr = 0.05), grad3)
r4 = optimizer_step(adamax(w3, lr = 0.05), grad3)
r5 = optimizer_step(rmsprop(w3, lr = 0.05), grad3)
r6 = optimizer_step(adagrad(w3, lr = 0.05), grad3)
r7 = optimizer_step(adadelta(w3), grad3)
print("nesterov_sgd -> {round(r1._params[0], 4)}, adamw -> {round(r2._params[0], 4)}, nadam -> {round(r3._params[0], 4)}")
print("adamax -> {round(r4._params[0], 4)}, rmsprop -> {round(r5._params[0], 4)}, adagrad -> {round(r6._params[0], 4)}, adadelta -> {round(r7._params[0], 4)}")

Xxor = [0.0, 0.0; 0.0, 1.0; 1.0, 0.0; 1.0, 1.0]
Yxor = [0.0; 1.0; 1.0; 2.0]
net = input(2) |> dense(4, activation = "relu") |> dense(1, activation = "none") |>
      compile(optimizer = lr_plateau(lr = 0.1, patience = 5, base = "adam"), loss = "mse", seed = 7)
net = net.fit(Xxor, Yxor, epochs = 60)
n = length(net.loss_history)
print("compile + fit(lr_plateau): loss {round(net.loss_history[0], 4)} -> {round(net.loss_history[n - 1], 4)}")

net2 = input(2) |> dense(4, activation = "relu") |> dense(1, activation = "none") |>
       compile(optimizer = lr_adaptive(lr = 0.05), loss = "mse", seed = 7)
net2 = net2.fit(Xxor, Yxor, epochs = 60)
n2 = length(net2.loss_history)
print("compile + fit(lr_adaptive): loss {round(net2.loss_history[0], 4)} -> {round(net2.loss_history[n2 - 1], 4)}")

quick = quick_mlp(Xxor, Yxor, seed = 3)
nq = length(quick.loss_history)
print("quick_mlp: loss {round(quick.loss_history[0], 4)} -> {round(quick.loss_history[nq - 1], 4)}")
output
train_loop (sgd): loss 30 -> 0
optimizer_step (adam): w -> 1.7775 (target 2.0)
nesterov_sgd -> 0.715, adamw -> 0.9495, nadam -> 0.9263
adamax -> 0.95, rmsprop -> 0.8419, adagrad -> 0.95, adadelta -> 0.9996
compile + fit(lr_plateau): loss 3.3387 -> 0.0341
compile + fit(lr_adaptive): loss 0.3897 -> 0.0002
quick_mlp: loss 3.1877 -> 0.0922

from statistics-ml

How it works

style ergonomics over the raw param/dense/relu/grad primitives above, WITHOUT the spec's (§38.4) unbuilt model ... end model / layer ... end layer grammar. Every piece here is an ordinary function returning Value::Record (an unfitted layer spec) or Value::Model (an initialized network) — the same "fit-style API via existing value shapes, no new syntax" convention kmeans_model/fit_scaler/ gru_init already established. See sequential_forward's own doc comment for how a spec+params pair actually runs. input(n) — starts a Tier-2 pipeline (Sequential pipeline API, 2026-08-26): a lightweight Value::Record tagged kind = "pipeline_input" tracking just the running output shape (out_dim, starting at n) and the layer-spec list built so far (empty here). Every dense(...) pipeline stage (see that builtin arm's own doc comment) reads and extends this same shape via eval_pipe's "piped value becomes the first argument" rule, and compile(...) turns the finished Record into a real sequential(...) model. Deliberately a DIFFERENT Record shape from dense_layer's own pipe-chain accumulation just below (kind="dense"|"dropout", checked by is_layer_spec) — two independent, non-colliding pipe-based ways to build a layer list, not one competing with the other.

From the note above this builtin in the interpreter, where the reasoning was written down as it was built.