Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions docs/BUILTINS.md
Original file line number Diff line number Diff line change
Expand Up @@ -397,10 +397,10 @@ automatically at exit.
| `sqrt` | `sqrt of t` | Element-wise square root; negative input returns 0 |
| `exp` | `exp of t` | Element-wise e^x; overflow saturates |
| `log` | `log of t` | Element-wise natural log; input is floored at 1e-10 |
| `softmax` | `softmax of t` | Row-wise softmax normalization |
| `log_softmax` | `log_softmax of t` | Row-wise log(softmax) |
| `relu` | `relu of t` | Element-wise max(0, x) |
| `leaky_relu` | `leaky_relu of t` | Element-wise max(0.01x, x) |
| `softmax` | `softmax of t` | Row-wise softmax normalization (a scalar is the one-element case → `1.0`) |
| `log_softmax` | `log_softmax of t` | Row-wise log(softmax) (a scalar → `log(1)` = `0.0`) |
| `relu` | `relu of t` | Element-wise max(0, x) (accepts a scalar) |
| `leaky_relu` | `leaky_relu of t` | Element-wise max(0.01x, x) (accepts a scalar) |

### Linear Algebra

Expand Down
14 changes: 14 additions & 0 deletions src/builtins_tensor.c
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,8 @@ Value* builtin_tensor_matmul(Value *arg) {

/* ==== BUILTIN: softmax ==== */
Value* builtin_tensor_softmax(Value *arg) {
/* #632: softmax of a single element normalizes to 1.0. */
if (arg && arg->type == VAL_NUM) return make_num(1.0);
int rows, cols;
double *flat = tensor_to_flat(arg, &rows, &cols);
if (!flat) return make_null();
Expand All @@ -424,6 +426,8 @@ Value* builtin_tensor_log_softmax(Value *arg) {
Value *first = arg->data.list.items[0];
if (first->type == VAL_LIST) tensor = first; /* [tensor, dim] form */
}
/* #632: log(softmax(scalar)) = log(1) = 0. */
if (tensor && tensor->type == VAL_NUM) return make_num(0.0);
int rows, cols;
double *flat = tensor_to_flat(tensor, &rows, &cols);
if (!flat) return make_null();
Expand All @@ -442,6 +446,11 @@ Value* builtin_tensor_log_softmax(Value *arg) {
/* ==== BUILTIN: relu ==== */
/* relu of tensor → element-wise max(0, x). Works on 1D or 2D. */
Value* builtin_tensor_relu(Value *arg) {
/* #632: a scalar is the degenerate element-wise case, like sqrt/exp/log. */
if (arg && arg->type == VAL_NUM) {
double x = arg->data.num;
return make_num(x < 0.0 ? 0.0 : x);
}
/* flat-buffer fast path: in-place clamp, shape preserved */
if (arg && arg->type == VAL_BUFFER) {
Value *res = make_buffer_like(arg);
Expand All @@ -468,6 +477,11 @@ Value* builtin_tensor_relu(Value *arg) {
/* ==== BUILTIN: leaky_relu ==== */
/* leaky_relu of tensor → element-wise max(0.01*x, x). Works on 1D or 2D. */
Value* builtin_tensor_leaky_relu(Value *arg) {
/* #632: scalar is the degenerate element-wise case. */
if (arg && arg->type == VAL_NUM) {
double x = arg->data.num;
return make_num(x < 0.0 ? 0.01 * x : x);
}
int rows, cols;
double *flat = tensor_to_flat(arg, &rows, &cols);
if (!flat) return make_null();
Expand Down
10 changes: 10 additions & 0 deletions tests/test_flat_buffer_tensor.eigs
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,14 @@ assert of [rsh[1] == 3, "reshape cols == 3"]
assert of [rs[0] == 7.0, "reshape preserves data[0]"]
assert of [rs[5] == 9.0, "reshape preserves data[5]"]

# #632: a scalar is the degenerate element-wise case. These four returned a
# silent null before the fix, which poisoned downstream arithmetic at the
# wrong line ((relu of -3) + 1 -> "cannot apply '+' to null and num").
assert of [(relu of (0 - 3)) == 0.0, "#632 relu of negative scalar is 0"]
assert of [(relu of 5.0) == 5.0, "#632 relu of positive scalar is x"]
assert of [(leaky_relu of (0 - 10.0)) == (0 - 0.1), "#632 leaky_relu of negative scalar is 0.01x"]
assert of [(softmax of 1.0) == 1.0, "#632 softmax of a scalar normalizes to 1"]
assert of [(log_softmax of 1.0) == 0.0, "#632 log_softmax of a scalar is log(1) = 0"]
assert of [((relu of (0 - 3)) + 1) == 1.0, "#632 scalar relu no longer poisons downstream arithmetic"]

print of "PASS: flat-buffer tensors"
Loading