Xenova HF Staff commited on
Commit
e394010
·
verified ·
1 Parent(s): a31d703

sync 2e7068faf55e

Browse files
README.md CHANGED
@@ -1,3 +1,73 @@
1
  ---
 
2
  license: apache-2.0
 
 
 
 
3
  ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ library_name: kernels
3
  license: apache-2.0
4
+ tags:
5
+ - kernel
6
+ - webgpu
7
+ - wgsl
8
  ---
9
+ # ai.onnx.Expand
10
+
11
+ `ai.onnx` · standard ONNX operator · ONNX opset ≥ 13
12
+
13
+ ## Description
14
+
15
+ Broadcasts `input` to a given `shape` following NumPy-style rules: dimensions are right-aligned, and corresponding dimensions must be equal or one of them must be 1. The output shape may differ from `shape` when a requested dimension is 1 or `shape` has fewer dimensions than `input`.
16
+
17
+ See the [ONNX `Expand` spec](https://onnx.ai/onnx/operators/onnx__Expand.html) for the reference semantics.
18
+
19
+ ## Inputs
20
+
21
+ | Name | Bind key | Logical dtype | WebGPU storage | Rank | Shape | Description | Presence |
22
+ | --- | --- | --- | --- | --- | --- | --- | --- |
23
+ | `input` | `input` | `T` | runtime-selected; narrow integers and bool use 32-bit slots | — | — | Input tensor to broadcast. | required |
24
+ | `shape` | `shape` | `S` | `uint32` | `1` | — | Logical int64 1-D tensor specifying the non-negative target shape; WebGPU stores it as uint32. | required |
25
+
26
+ ## Outputs
27
+
28
+ | Name | Bind key | Logical dtype | Rank | Shape | Description | Presence |
29
+ | --- | --- | --- | --- | --- | --- | --- |
30
+ | `output` | `output` | `T` | derived | — | Output tensor with the broadcasted shape. | required |
31
+
32
+ ## Type constraints
33
+
34
+ | Variable | Allowed dtypes |
35
+ | --- | --- |
36
+ | `T` | `float32`, `float16`, `uint32`, `int32`, `int16`, `uint8`, `int8`, `bool` |
37
+ | `S` | `int64` |
38
+
39
+ ## Files
40
+
41
+ - [`metadata.json`](build/webgpu/metadata.json) — kernel metadata (id, digests, provenance)
42
+ - [`manifest.json`](build/webgpu/manifest.json) — the op contract (source of truth)
43
+ - [`test.json`](build/webgpu/test.json) — correctness cases
44
+ - [`bench.json`](build/webgpu/bench.json) — benchmark + tuning cases
45
+ - [`expand-vec4.wgsl.jinja`](build/webgpu/expand-vec4.wgsl.jinja)
46
+ - [`expand.wgsl.jinja`](build/webgpu/expand.wgsl.jinja)
47
+
48
+ ## Use with `@huggingface/kernels`
49
+
50
+ The loader automatically allocates outputs whose metadata it can derive from the manifest contract and this call.
51
+
52
+ The explicit `outputs` entries provide shape and logical dtype metadata for the results listed below:
53
+
54
+ - `output`
55
+
56
+ Each entry either requests an optional result or supplies metadata that cannot be inferred from the inputs.
57
+
58
+ The `version: 1` option selects the published kernel contract; it is independent of any operator opset, contrib `since_version`, or model version.
59
+
60
+ Replace each `*Data` placeholder with a typed array containing the corresponding input data.
61
+
62
+ ```js
63
+ import { getKernel } from "@huggingface/kernels";
64
+
65
+ const kernel = await getKernel("webgpu-kernels/ai.onnx.Expand", { version: 1 });
66
+ // Explicit destinations request optional results or supply metadata that cannot be inferred.
67
+ const { output } = await kernel({
68
+ input: { data: inputData, shape: [1, 4] },
69
+ shape: { data: shapeData, shape: [2] },
70
+ }, {
71
+ outputs: { output: { shape: [2, 4], dtype: "int16" } },
72
+ });
73
+ ```
build/webgpu/bench.json ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "op": "ai.onnx.Expand",
3
+ "tunableSpace": { "WORKGROUP_SIZE": [64, 128, 256] },
4
+ "cases": [
5
+ {
6
+ "name": "expand-f32-1m",
7
+ "preset": "smoke",
8
+ "vars": { "dtype": "float32", "count": 1048576 },
9
+ "inputs": {
10
+ "input": { "shape": [1, 1024], "dtype": "float32", "dist": "normal", "seed": 860, "scale": 1 },
11
+ "shape": { "shape": [2], "dtype": "uint32", "data": { "kind": "values", "values": [1024, 1024] } }
12
+ },
13
+ "outputs": { "output": { "shape": [1024, 1024], "dtype": "float32" } },
14
+ "bench": {
15
+ "primary": true,
16
+ "metrics": [{ "type": "bandwidth", "value": "args.count * dtypeBytes(args.dtype) * 2" }]
17
+ }
18
+ },
19
+ {
20
+ "name": "expand-u32-bool-like-1m",
21
+ "preset": "edge",
22
+ "vars": { "dtype": "uint32", "count": 1048576 },
23
+ "inputs": {
24
+ "input": { "shape": [1, 1024], "dtype": "uint32", "dist": "linearMod", "mod": 2 },
25
+ "shape": { "shape": [2], "dtype": "uint32", "data": { "kind": "values", "values": [1024, 1024] } }
26
+ },
27
+ "outputs": { "output": { "shape": [1024, 1024], "dtype": "uint32" } },
28
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "args.count * dtypeBytes(args.dtype) * 2" }] }
29
+ },
30
+ {
31
+ "name": "expand-f32-scalar-fallback-1m",
32
+ "preset": "stress",
33
+ "vars": { "dtype": "float32", "count": 1049600 },
34
+ "inputs": {
35
+ "input": { "shape": [1, 1025], "dtype": "float32", "dist": "normal", "seed": 42, "scale": 1 },
36
+ "shape": { "shape": [2], "dtype": "uint32", "data": { "kind": "values", "values": [1024, 1025] } }
37
+ },
38
+ "outputs": { "output": { "shape": [1024, 1025], "dtype": "float32" } },
39
+ "bench": { "metrics": [{ "type": "bandwidth", "value": "args.count * dtypeBytes(args.dtype) * 2" }] }
40
+ }
41
+ ]
42
+ }
build/webgpu/expand-vec4.wgsl.jinja ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% if usesF16 %}
2
+ enable f16;
3
+ {% endif %}
4
+ {{ env.wgsl.resourceDeclarations }}
5
+
6
+ {% set x_numel = namespace(value=1) %}
7
+ {% for d in source.xShape %}{% set x_numel.value = x_numel.value * d %}{% endfor %}
8
+ {% set x_same = namespace(value=(source.xRank == source.yRank)) %}
9
+ {% if x_same.value %}
10
+ {% for axis in range(source.yRank) %}
11
+ {% if source.xShape[axis] != source.yShape[axis] %}{% set x_same.value = false %}{% endif %}
12
+ {% endfor %}
13
+ {% endif %}
14
+ {% set x_inner = source.xShape[source.xRank - 1] if source.xRank >= 1 else 1 %}
15
+ {% if x_numel.value == 1 %}{% set x_mode = "scalar" %}
16
+ {% elif x_inner == 1 %}{% set x_mode = "splat" %}
17
+ {% else %}{% set x_mode = "contig" %}{% endif %}
18
+ {% set xUsesIndex = namespace(value=false) %}
19
+ {% for axis in range(source.yRank) %}
20
+ {% set x_axis = axis - (source.yRank - source.xRank) %}
21
+ {% if x_axis >= 0 and source.xShape[x_axis] != 1 %}{% set xUsesIndex.value = true %}{% endif %}
22
+ {% endfor %}
23
+
24
+ {% if x_mode == "scalar" %}
25
+ // Each invocation splats the single input value across four consecutive outputs.
26
+ {% elif x_mode == "splat" %}
27
+ // Each invocation broadcasts one innermost-axis value across four outputs;
28
+ // x_offset applies any outer-axis broadcasting once for the group.
29
+ {% else %}
30
+ // Each invocation copies four contiguous input values. x_offset applies any
31
+ // outer-axis broadcasting once for the group.
32
+ {% endif %}
33
+ {% if x_mode != "scalar" %}
34
+ fn x_offset(out_index: u32) -> u32 {
35
+ {% if x_same.value %}
36
+ return out_index;
37
+ {% else %}
38
+ {% if xUsesIndex.value %}
39
+ var rem = out_index;
40
+ {% endif %}
41
+ var offset = 0u;
42
+ // Empty output axes can produce a zero trailing stride. Their dispatch is
43
+ // empty, but the module must still compile, so zero strides use a harmless
44
+ // divisor of one instead of emitting a constant division by zero.
45
+ {% for axis in range(source.yRank) %}
46
+ {% set y_stride = namespace(value=1) %}
47
+ {% for j in range(axis + 1, source.yRank) %}
48
+ {% set y_stride.value = y_stride.value * source.yShape[j] %}
49
+ {% endfor %}
50
+ {% set y_div = y_stride.value if y_stride.value != 0 else 1 %}
51
+ {% set x_axis = axis - (source.yRank - source.xRank) %}
52
+ {% if x_axis >= 0 and source.xShape[x_axis] != 1 %}
53
+ let coord{{ axis }} = rem / {{ y_div }}u;
54
+ rem = rem % {{ y_div }}u;
55
+ {% set x_stride = namespace(value=1) %}
56
+ {% for j in range(x_axis + 1, source.xRank) %}
57
+ {% set x_stride.value = x_stride.value * source.xShape[j] %}
58
+ {% endfor %}
59
+ offset = offset + coord{{ axis }} * {{ x_stride.value }}u;
60
+ {% elif xUsesIndex.value %}
61
+ rem = rem % {{ y_div }}u;
62
+ {% endif %}
63
+ {% endfor %}
64
+ return offset;
65
+ {% endif %}
66
+ }
67
+ {% endif %}
68
+
69
+ @compute @workgroup_size({{ tunables.WORKGROUP_SIZE }})
70
+ fn main(@builtin(global_invocation_id) gid: vec3<u32>, @builtin(num_workgroups) nwg: vec3<u32>) {
71
+ // 2D-folded flat vec4 index: gid.y carries the high bits past the
72
+ // maxComputeWorkgroupsPerDimension limit (the dispatch caps x and spills into y).
73
+ let i4 = gid.x + gid.y * nwg.x * {{ tunables.WORKGROUP_SIZE }}u;
74
+ if (i4 >= params.count) {
75
+ return;
76
+ }
77
+ {% if x_mode != "scalar" %}
78
+ let base = i4 * 4u;
79
+ {% endif %}
80
+ {% if x_mode == "scalar" %}
81
+ y[i4] = {{ vectorScalar }}(x[0]);
82
+ {% elif x_mode == "splat" %}
83
+ y[i4] = {{ vectorScalar }}(x[x_offset(base)]);
84
+ {% else %}
85
+ let xo = x_offset(base);
86
+ y[i4] = {{ vectorScalar }}(x[xo], x[xo + 1u], x[xo + 2u], x[xo + 3u]);
87
+ {% endif %}
88
+ }
build/webgpu/expand.wgsl.jinja ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% if usesF16 %}
2
+ enable f16;
3
+ {% endif %}
4
+ {{ env.wgsl.resourceDeclarations }}
5
+
6
+ {% set xUsesIndex = namespace(value=false) %}
7
+ {% for axis in range(source.yRank) %}
8
+ {% set x_axis = axis - (source.yRank - source.xRank) %}
9
+ {% if x_axis >= 0 and source.xShape[x_axis] != 1 %}{% set xUsesIndex.value = true %}{% endif %}
10
+ {% endfor %}
11
+ fn x_offset({% if xUsesIndex.value %}out_index: u32{% endif %}) -> u32 {
12
+ {% if xUsesIndex.value %}
13
+ var rem = out_index;
14
+ {% endif %}
15
+ var offset = 0u;
16
+ // Empty output axes can produce a zero trailing stride. Their dispatch is
17
+ // empty, but the module must still compile, so zero strides use a harmless
18
+ // divisor of one instead of emitting a constant division by zero.
19
+ {% for axis in range(source.yRank) %}
20
+ {% set y_stride = namespace(value=1) %}
21
+ {% for j in range(axis + 1, source.yRank) %}
22
+ {% set y_stride.value = y_stride.value * source.yShape[j] %}
23
+ {% endfor %}
24
+ {% set y_div = y_stride.value if y_stride.value != 0 else 1 %}
25
+ {% set x_axis = axis - (source.yRank - source.xRank) %}
26
+ {% if x_axis >= 0 and source.xShape[x_axis] != 1 %}
27
+ let coord{{ axis }} = rem / {{ y_div }}u;
28
+ rem = rem % {{ y_div }}u;
29
+ {% set x_stride = namespace(value=1) %}
30
+ {% for j in range(x_axis + 1, source.xRank) %}
31
+ {% set x_stride.value = x_stride.value * source.xShape[j] %}
32
+ {% endfor %}
33
+ offset = offset + coord{{ axis }} * {{ x_stride.value }}u;
34
+ {% elif xUsesIndex.value %}
35
+ rem = rem % {{ y_div }}u;
36
+ {% endif %}
37
+ {% endfor %}
38
+ return offset;
39
+ }
40
+
41
+ @compute @workgroup_size({{ tunables.WORKGROUP_SIZE }})
42
+ fn main(@builtin(global_invocation_id) gid: vec3<u32>, @builtin(num_workgroups) nwg: vec3<u32>) {
43
+ // 2D-folded flat index: gid.y carries the high bits past the
44
+ // maxComputeWorkgroupsPerDimension dispatch limit (outputs > 16.7M elements).
45
+ let i = gid.x + gid.y * nwg.x * {{ tunables.WORKGROUP_SIZE }}u;
46
+ if (i >= params.count) {
47
+ return;
48
+ }
49
+ y[i] = x[x_offset({% if xUsesIndex.value %}i{% endif %})];
50
+ }
build/webgpu/manifest.json ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "domain": "ai.onnx",
3
+ "name": "Expand",
4
+ "sinceVersion": 13,
5
+ "description": "Broadcasts `input` to a given `shape` following NumPy-style rules: dimensions are right-aligned, and corresponding dimensions must be equal or one of them must be 1. The output shape may differ from `shape` when a requested dimension is 1 or `shape` has fewer dimensions than `input`.",
6
+ "inputs": [
7
+ { "role": "input", "dtype": "T", "description": "Input tensor to broadcast." },
8
+ {
9
+ "role": "shape",
10
+ "dtype": "S",
11
+ "description": "Logical int64 1-D tensor specifying the non-negative target shape; WebGPU stores it as uint32.",
12
+ "rank": 1
13
+ }
14
+ ],
15
+ "outputs": [
16
+ {
17
+ "role": "output",
18
+ "dtype": "T",
19
+ "description": "Output tensor with the broadcasted shape.",
20
+ "rank": "dim(shapes.shape, 0)"
21
+ }
22
+ ],
23
+ "typeConstraints": {
24
+ "T": ["float32", "float16", "uint32", "int32", "int16", "uint8", "int8", "bool"],
25
+ "S": ["int64"]
26
+ },
27
+ "args": {
28
+ "input": { "kind": "tensor", "semantic": "input", "role": "input" },
29
+ "shape": { "kind": "tensor", "semantic": "shape", "role": "shape", "dtype": "uint32", "narrowing": "checked" },
30
+ "output": { "kind": "tensor", "semantic": "output", "role": "output" }
31
+ },
32
+ "tunables": { "WORKGROUP_SIZE": 256 },
33
+ "constants": { "scalar": "dtypes.T", "usesF16": "dtypes.T == \"f16\"" },
34
+ "variants": [
35
+ {
36
+ "id": "broadcast_vec4",
37
+ "priority": 10,
38
+ "when": ["ranks.output >= 1", "ranks.input <= ranks.output", "f16Ok(dtypes.T)", "dim(shapes.output, -1) % 4 == 0"],
39
+ "constants": { "vectorScalar": "\"vec4<\" ~ dtypes.T ~ \">\"" },
40
+ "passes": [
41
+ {
42
+ "id": "main",
43
+ "name": "Expand.vec4",
44
+ "source": {
45
+ "shader": "expand-vec4.wgsl.jinja",
46
+ "inputs": {
47
+ "xShape": "shapes.input",
48
+ "yShape": "shapes.output",
49
+ "xRank": "ranks.input",
50
+ "yRank": "ranks.output"
51
+ }
52
+ },
53
+ "bindings": [
54
+ {
55
+ "name": "x",
56
+ "arg": "input",
57
+ "semantic": "input",
58
+ "buffer": { "type": "read-only-storage" },
59
+ "elementType": "$scalar"
60
+ },
61
+ {
62
+ "name": "y",
63
+ "arg": "output",
64
+ "semantic": "output",
65
+ "buffer": { "type": "storage" },
66
+ "elementType": "$vectorScalar"
67
+ },
68
+ {
69
+ "name": "params",
70
+ "semantic": "kernel.params",
71
+ "buffer": { "type": "uniform" },
72
+ "struct": {
73
+ "name": "Params",
74
+ "fields": [{ "name": "count", "type": "u32", "value": "numel(shapes.output) / 4" }]
75
+ }
76
+ }
77
+ ],
78
+ "dispatch": { "threads": "numel(shapes.output) / 4", "workgroupSize": "tunables.WORKGROUP_SIZE" }
79
+ }
80
+ ]
81
+ },
82
+ {
83
+ "id": "broadcast",
84
+ "when": ["ranks.input <= ranks.output", "f16Ok(dtypes.T)"],
85
+ "passes": [
86
+ {
87
+ "id": "main",
88
+ "name": "Expand",
89
+ "source": {
90
+ "shader": "expand.wgsl.jinja",
91
+ "inputs": {
92
+ "xShape": "shapes.input",
93
+ "yShape": "shapes.output",
94
+ "xRank": "ranks.input",
95
+ "yRank": "ranks.output"
96
+ }
97
+ },
98
+ "bindings": [
99
+ {
100
+ "name": "x",
101
+ "arg": "input",
102
+ "semantic": "input",
103
+ "buffer": { "type": "read-only-storage" },
104
+ "elementType": "$scalar"
105
+ },
106
+ {
107
+ "name": "y",
108
+ "arg": "output",
109
+ "semantic": "output",
110
+ "buffer": { "type": "storage" },
111
+ "elementType": "$scalar"
112
+ },
113
+ {
114
+ "name": "params",
115
+ "semantic": "kernel.params",
116
+ "buffer": { "type": "uniform" },
117
+ "struct": {
118
+ "name": "Params",
119
+ "fields": [{ "name": "count", "type": "u32", "value": "numel(shapes.output)" }]
120
+ }
121
+ }
122
+ ],
123
+ "dispatch": { "threads": "numel(shapes.output)", "workgroupSize": "tunables.WORKGROUP_SIZE" }
124
+ }
125
+ ]
126
+ }
127
+ ]
128
+ }
build/webgpu/metadata.json ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "ai.onnx.Expand",
3
+ "id": "_ai_onnx_expand_webgpu_54cd655",
4
+ "version": 1,
5
+ "license": "Apache-2.0",
6
+ "backend": { "type": "webgpu" },
7
+ "digest": {
8
+ "algorithm": "sha256",
9
+ "files": {
10
+ "bench.json": "RLidqSlxqJDOxs+FeBKGm1VWNsXk2nLH7N+hyCych0Q=",
11
+ "expand-vec4.wgsl.jinja": "aiqKbsXQ+vUgxM55kKrOrVbpcLgvJzXSenpuGx+/C/w=",
12
+ "expand.wgsl.jinja": "LurmTZjbk5/Jtet50CvC5vPLooK/k4cPHmlEWHi3k64=",
13
+ "manifest.json": "GHAUTVFssEJLTI/FFhC0SV610+2xmx65imK6FCmKRk0=",
14
+ "test.json": "T6kUaQLTGfJvF6V4kE+IwKWM2zmZu8QuPHyo+iy+HJs="
15
+ }
16
+ },
17
+ "provenance": { "kernel": { "sha": "2e7068faf55e7f43df740015f6d1ee49391a41c5", "dirty": false } },
18
+ "webgpu": { "manifestSpec": "1.0", "specialized": true, "opPath": "ops/ai.onnx.Expand" }
19
+ }
build/webgpu/test.json ADDED
@@ -0,0 +1,607 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "op": "ai.onnx.Expand",
3
+ "cases": [
4
+ {
5
+ "name": "int16_broadcast_boundaries",
6
+ "inputs": {
7
+ "input": { "dtype": "int16", "shape": [1, 4], "data": { "kind": "values", "values": [-32768, -1, 0, 32767] } },
8
+ "shape": { "dtype": "uint32", "shape": [2], "data": { "kind": "values", "values": [2, 4] } }
9
+ },
10
+ "outputs": {
11
+ "output": {
12
+ "dtype": "int16",
13
+ "shape": [2, 4],
14
+ "tolerance": 0,
15
+ "data": { "kind": "values", "values": [-32768, -1, 0, 32767, -32768, -1, 0, 32767] }
16
+ }
17
+ }
18
+ },
19
+ {
20
+ "name": "dispatch_cliff_scalar_splat",
21
+ "inputs": {
22
+ "input": { "dtype": "float32", "shape": [1], "data": { "kind": "values", "values": [7.0] } },
23
+ "shape": { "dtype": "uint32", "shape": [1], "data": { "kind": "values", "values": [16776963] } }
24
+ },
25
+ "outputs": { "output": { "dtype": "float32", "shape": [16776963], "tolerance": 0 } }
26
+ },
27
+ {
28
+ "name": "scalar_to_3x3",
29
+ "inputs": {
30
+ "input": { "dtype": "float32", "shape": [1], "data": { "kind": "values", "values": [2.5] } },
31
+ "shape": { "dtype": "uint32", "shape": [2], "data": { "kind": "values", "values": [3, 3] } }
32
+ },
33
+ "outputs": { "output": { "dtype": "float32", "shape": [3, 3], "tolerance": 0.000001 } }
34
+ },
35
+ {
36
+ "name": "ort_float_scalar_to_3x3",
37
+ "provenance": {
38
+ "source": "onnxruntime/test/providers/cpu/tensor/expand_test.cc",
39
+ "test": "ExpandOpTest.Expand_3x3"
40
+ },
41
+ "inputs": {
42
+ "input": { "dtype": "float32", "shape": [1], "data": { "kind": "values", "values": [1.0] } },
43
+ "shape": { "dtype": "uint32", "shape": [2], "data": { "kind": "values", "values": [3, 3] } }
44
+ },
45
+ "outputs": { "output": { "dtype": "float32", "shape": [3, 3], "tolerance": 0.000001 } }
46
+ },
47
+ {
48
+ "name": "row_vector_to_3x3",
49
+ "inputs": {
50
+ "input": { "dtype": "float32", "shape": [1, 3], "data": { "kind": "values", "values": [1.0, 2.0, 3.0] } },
51
+ "shape": { "dtype": "uint32", "shape": [2], "data": { "kind": "values", "values": [3, 3] } }
52
+ },
53
+ "outputs": { "output": { "dtype": "float32", "shape": [3, 3], "tolerance": 0.000001 } }
54
+ },
55
+ {
56
+ "name": "ort_float_vector_to_rows",
57
+ "provenance": {
58
+ "source": "onnxruntime/test/providers/cpu/tensor/expand_test.cc",
59
+ "test": "ExpandOpTest.Expand_3x1"
60
+ },
61
+ "inputs": {
62
+ "input": { "dtype": "float32", "shape": [3], "data": { "kind": "values", "values": [1.0, 2.0, 3.0] } },
63
+ "shape": { "dtype": "uint32", "shape": [2], "data": { "kind": "values", "values": [3, 1] } }
64
+ },
65
+ "outputs": { "output": { "dtype": "float32", "shape": [3, 3], "tolerance": 0.000001 } }
66
+ },
67
+ {
68
+ "name": "col_vector_to_3x3",
69
+ "inputs": {
70
+ "input": { "dtype": "float32", "shape": [3, 1], "data": { "kind": "values", "values": [1.0, 2.0, 3.0] } },
71
+ "shape": { "dtype": "uint32", "shape": [2], "data": { "kind": "values", "values": [3, 3] } }
72
+ },
73
+ "outputs": { "output": { "dtype": "float32", "shape": [3, 3], "tolerance": 0.000001 } }
74
+ },
75
+ {
76
+ "name": "ort_float_col_vector_to_cols",
77
+ "provenance": {
78
+ "source": "onnxruntime/test/providers/cpu/tensor/expand_test.cc",
79
+ "test": "ExpandOpTest.Expand_1x3"
80
+ },
81
+ "inputs": {
82
+ "input": { "dtype": "float32", "shape": [3, 1], "data": { "kind": "values", "values": [1.0, 2.0, 3.0] } },
83
+ "shape": { "dtype": "uint32", "shape": [2], "data": { "kind": "values", "values": [1, 3] } }
84
+ },
85
+ "outputs": { "output": { "dtype": "float32", "shape": [3, 3], "tolerance": 0.000001 } }
86
+ },
87
+ {
88
+ "name": "rank3_broadcast",
89
+ "inputs": {
90
+ "input": {
91
+ "dtype": "float32",
92
+ "shape": [1, 3, 1],
93
+ "data": { "kind": "fillFloat32", "sinStep": 0.13, "cosStep": 0.29 }
94
+ },
95
+ "shape": { "dtype": "uint32", "shape": [3], "data": { "kind": "values", "values": [2, 3, 4] } }
96
+ },
97
+ "outputs": { "output": { "dtype": "float32", "shape": [2, 3, 4], "tolerance": 0.000001 } }
98
+ },
99
+ {
100
+ "name": "uint32_bool_like_broadcast",
101
+ "inputs": {
102
+ "input": { "dtype": "uint32", "shape": [1, 3, 1], "data": { "kind": "values", "values": [1, 0, 2] } },
103
+ "shape": { "dtype": "uint32", "shape": [3], "data": { "kind": "values", "values": [2, 3, 4] } }
104
+ },
105
+ "outputs": { "output": { "dtype": "uint32", "shape": [2, 3, 4], "tolerance": 0 } }
106
+ },
107
+ {
108
+ "name": "rank5_broadcast",
109
+ "inputs": {
110
+ "input": {
111
+ "dtype": "float32",
112
+ "shape": [2, 1, 2, 1, 1],
113
+ "data": { "kind": "fillFloat32", "sinStep": 0.11, "cosStep": 0.23 }
114
+ },
115
+ "shape": { "dtype": "uint32", "shape": [5], "data": { "kind": "values", "values": [2, 3, 2, 4, 2] } }
116
+ },
117
+ "outputs": { "output": { "dtype": "float32", "shape": [2, 3, 2, 4, 2], "tolerance": 0.000001 } }
118
+ },
119
+ {
120
+ "name": "rank7_broadcast",
121
+ "inputs": {
122
+ "input": {
123
+ "dtype": "float32",
124
+ "shape": [1, 2, 1, 3, 1, 1, 2],
125
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.19 }
126
+ },
127
+ "shape": { "dtype": "uint32", "shape": [7], "data": { "kind": "values", "values": [2, 2, 4, 3, 2, 3, 2] } }
128
+ },
129
+ "outputs": { "output": { "dtype": "float32", "shape": [2, 2, 4, 3, 2, 3, 2], "tolerance": 0.000001 } }
130
+ },
131
+ {
132
+ "name": "true_scalar_to_rank3",
133
+ "inputs": {
134
+ "input": { "dtype": "float32", "shape": [], "data": { "kind": "values", "values": [-2.5] } },
135
+ "shape": { "dtype": "uint32", "shape": [3], "data": { "kind": "values", "values": [2, 2, 3] } }
136
+ },
137
+ "outputs": { "output": { "dtype": "float32", "shape": [2, 2, 3], "tolerance": 0.000001 } }
138
+ },
139
+ {
140
+ "name": "scalar_to_scalar_empty_shape",
141
+ "inputs": {
142
+ "input": { "dtype": "float32", "shape": [], "data": { "kind": "values", "values": [6.5] } },
143
+ "shape": { "dtype": "uint32", "shape": [0], "data": { "kind": "values", "values": [] } }
144
+ },
145
+ "outputs": { "output": { "dtype": "float32", "shape": [], "tolerance": 0.000001 } }
146
+ },
147
+ {
148
+ "name": "broadcast_to_zero_width_rows",
149
+ "provenance": {
150
+ "source": "onnxruntime/test/providers/cpu/tensor/expand_test.cc",
151
+ "test": "ExpandOpTest.Expand_3x1",
152
+ "notes": "Valid empty-output broadcast: input shape [1,0] expands to [3,0]. No elements are written, but generated stride math must still compile."
153
+ },
154
+ "inputs": {
155
+ "input": { "dtype": "float32", "shape": [1, 0], "data": { "kind": "values", "values": [] } },
156
+ "shape": { "dtype": "uint32", "shape": [2], "data": { "kind": "values", "values": [3, 0] } }
157
+ },
158
+ "outputs": {
159
+ "output": { "dtype": "float32", "shape": [3, 0], "tolerance": 0, "data": { "kind": "values", "values": [] } }
160
+ }
161
+ },
162
+ {
163
+ "name": "broadcast_to_zero_middle_dim_scalar",
164
+ "provenance": {
165
+ "source": "onnxruntime/test/providers/cpu/tensor/expand_test.cc",
166
+ "test": "ExpandOpTest.Expand_3x1x3x1_int64",
167
+ "notes": "Scalar-template companion for zero-sized broadcast output: the final dimension is not vec4-aligned, so the generic Expand shader must handle zero strides."
168
+ },
169
+ "inputs": {
170
+ "input": { "dtype": "float32", "shape": [1, 0, 5], "data": { "kind": "values", "values": [] } },
171
+ "shape": { "dtype": "uint32", "shape": [3], "data": { "kind": "values", "values": [3, 0, 5] } }
172
+ },
173
+ "outputs": {
174
+ "output": { "dtype": "float32", "shape": [3, 0, 5], "tolerance": 0, "data": { "kind": "values", "values": [] } }
175
+ }
176
+ },
177
+ {
178
+ "name": "ort_int32_scalar_to_3x3",
179
+ "provenance": {
180
+ "source": "onnxruntime/test/providers/cpu/tensor/expand_test.cc",
181
+ "test": "ExpandOpTest.Expand_3x3_int32"
182
+ },
183
+ "inputs": {
184
+ "input": { "dtype": "int32", "shape": [1], "data": { "kind": "values", "values": [1] } },
185
+ "shape": { "dtype": "uint32", "shape": [2], "data": { "kind": "values", "values": [3, 3] } }
186
+ },
187
+ "outputs": { "output": { "dtype": "int32", "shape": [3, 3], "tolerance": 0 } }
188
+ },
189
+ {
190
+ "name": "ort_int32_vector_to_rows",
191
+ "provenance": {
192
+ "source": "onnxruntime/test/providers/cpu/tensor/expand_test.cc",
193
+ "test": "ExpandOpTest.Expand_3x1_int32"
194
+ },
195
+ "inputs": {
196
+ "input": { "dtype": "int32", "shape": [3], "data": { "kind": "values", "values": [1, 2, 3] } },
197
+ "shape": { "dtype": "uint32", "shape": [2], "data": { "kind": "values", "values": [3, 1] } }
198
+ },
199
+ "outputs": { "output": { "dtype": "int32", "shape": [3, 3], "tolerance": 0 } }
200
+ },
201
+ {
202
+ "name": "ort_int32_rank4_singletons",
203
+ "provenance": {
204
+ "source": "onnxruntime/test/providers/cpu/tensor/expand_test.cc",
205
+ "test": "ExpandOpTest.Expand_3x1x3x1_int64",
206
+ "notes": "Same rank-4 singleton broadcast pattern adapted to int32 storage."
207
+ },
208
+ "inputs": {
209
+ "input": {
210
+ "dtype": "int32",
211
+ "shape": [1, 3, 1, 3],
212
+ "data": { "kind": "values", "values": [1, 2, 3, 4, 5, 6, 7, 8, 9] }
213
+ },
214
+ "shape": { "dtype": "uint32", "shape": [4], "data": { "kind": "values", "values": [3, 3, 3, 3] } }
215
+ },
216
+ "outputs": { "output": { "dtype": "int32", "shape": [3, 3, 3, 3], "tolerance": 0 } }
217
+ },
218
+ {
219
+ "name": "ort_f16_scalar_to_3x3",
220
+ "provenance": {
221
+ "source": "onnxruntime/test/providers/cpu/tensor/expand_test.cc",
222
+ "test": "ExpandOpTest.Expand_3x3_float16"
223
+ },
224
+ "inputs": {
225
+ "input": { "dtype": "float16", "shape": [1], "data": { "kind": "values", "values": [1.0] } },
226
+ "shape": { "dtype": "uint32", "shape": [2], "data": { "kind": "values", "values": [3, 3] } }
227
+ },
228
+ "outputs": { "output": { "dtype": "float16", "shape": [3, 3], "tolerance": 0.001 } }
229
+ },
230
+ {
231
+ "name": "ort_f16_vector_to_rows",
232
+ "provenance": {
233
+ "source": "onnxruntime/test/providers/cpu/tensor/expand_test.cc",
234
+ "test": "ExpandOpTest.Expand_3x1_float16"
235
+ },
236
+ "inputs": {
237
+ "input": { "dtype": "float16", "shape": [3], "data": { "kind": "values", "values": [1.0, 2.0, 3.0] } },
238
+ "shape": { "dtype": "uint32", "shape": [2], "data": { "kind": "values", "values": [3, 1] } }
239
+ },
240
+ "outputs": { "output": { "dtype": "float16", "shape": [3, 3], "tolerance": 0.001 } }
241
+ },
242
+ {
243
+ "name": "ort_f16_col_vector_to_cols",
244
+ "provenance": {
245
+ "source": "onnxruntime/test/providers/cpu/tensor/expand_test.cc",
246
+ "test": "ExpandOpTest.Expand_1x3_float16"
247
+ },
248
+ "inputs": {
249
+ "input": { "dtype": "float16", "shape": [3, 1], "data": { "kind": "values", "values": [1.0, 2.0, 3.0] } },
250
+ "shape": { "dtype": "uint32", "shape": [2], "data": { "kind": "values", "values": [1, 3] } }
251
+ },
252
+ "outputs": { "output": { "dtype": "float16", "shape": [3, 3], "tolerance": 0.001 } }
253
+ },
254
+ {
255
+ "name": "ort_uint32_bool_scalar_to_3x3",
256
+ "provenance": {
257
+ "source": "onnxruntime/test/providers/cpu/tensor/expand_test.cc",
258
+ "test": "ExpandOpTest.Expand_3x3_bool",
259
+ "notes": "Adapts ORT's bool tensor to logical uint32 values because this framework stores bool-like tensors as u32 slots."
260
+ },
261
+ "inputs": {
262
+ "input": { "dtype": "uint32", "shape": [1], "data": { "kind": "values", "values": [1] } },
263
+ "shape": { "dtype": "uint32", "shape": [2], "data": { "kind": "values", "values": [3, 3] } }
264
+ },
265
+ "outputs": { "output": { "dtype": "uint32", "shape": [3, 3], "tolerance": 0 } }
266
+ },
267
+ {
268
+ "name": "ort_uint32_bool_col_to_four_cols",
269
+ "provenance": {
270
+ "source": "onnxruntime/test/providers/cpu/tensor/expand_test.cc",
271
+ "test": "ExpandOpTest.Expand_1x4_bool",
272
+ "notes": "Adapts ORT's bool tensor to logical uint32 values because this framework stores bool-like tensors as u32 slots."
273
+ },
274
+ "inputs": {
275
+ "input": { "dtype": "uint32", "shape": [3, 1], "data": { "kind": "values", "values": [0, 1, 0] } },
276
+ "shape": { "dtype": "uint32", "shape": [2], "data": { "kind": "values", "values": [1, 4] } }
277
+ },
278
+ "outputs": { "output": { "dtype": "uint32", "shape": [3, 4], "tolerance": 0 } }
279
+ },
280
+ {
281
+ "name": "ort_shape_dim_one_does_not_shrink_rank5",
282
+ "provenance": {
283
+ "source": "onnxruntime/test/providers/cpu/tensor/expand_test.cc",
284
+ "test": "ExpandOpTest.Expand_2x2x1x2x1_float"
285
+ },
286
+ "inputs": {
287
+ "input": {
288
+ "dtype": "float32",
289
+ "shape": [2, 2, 1, 2, 1],
290
+ "data": { "kind": "values", "values": [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0] }
291
+ },
292
+ "shape": { "dtype": "uint32", "shape": [5], "data": { "kind": "values", "values": [1, 2, 2, 2, 2] } }
293
+ },
294
+ "outputs": { "output": { "dtype": "float32", "shape": [2, 2, 2, 2, 2], "tolerance": 0.000001 } }
295
+ },
296
+ {
297
+ "name": "ort_shape_dim_one_does_not_shrink_middle",
298
+ "provenance": {
299
+ "source": "onnxruntime/test/providers/cpu/tensor/expand_test.cc",
300
+ "test": "ExpandOpTest.Expand_3x1x8_float"
301
+ },
302
+ "inputs": {
303
+ "input": {
304
+ "dtype": "float32",
305
+ "shape": [3, 2, 1],
306
+ "data": { "kind": "values", "values": [1.0, 2.0, 3.0, 4.0, 5.0, 6.0] }
307
+ },
308
+ "shape": { "dtype": "uint32", "shape": [3], "data": { "kind": "values", "values": [3, 1, 8] } }
309
+ },
310
+ "outputs": { "output": { "dtype": "float32", "shape": [3, 2, 8], "tolerance": 0.000001 } }
311
+ },
312
+ {
313
+ "name": "ort_int32_col_vector_to_cols",
314
+ "provenance": {
315
+ "source": "onnxruntime/test/providers/cpu/tensor/expand_test.cc",
316
+ "test": "ExpandOpTest.Expand_1x3_int32"
317
+ },
318
+ "inputs": {
319
+ "input": { "dtype": "int32", "shape": [3, 1], "data": { "kind": "values", "values": [1, 2, 3] } },
320
+ "shape": { "dtype": "uint32", "shape": [2], "data": { "kind": "values", "values": [1, 3] } }
321
+ },
322
+ "outputs": { "output": { "dtype": "int32", "shape": [3, 3], "tolerance": 0 } }
323
+ },
324
+ {
325
+ "name": "ort_uint32_bool_col_to_cols",
326
+ "provenance": {
327
+ "source": "onnxruntime/test/providers/cpu/tensor/expand_test.cc",
328
+ "test": "ExpandOpTest.Expand_1x3_bool",
329
+ "notes": "Adapts ORT's bool tensor to logical uint32 values because this framework stores bool-like tensors as u32 slots."
330
+ },
331
+ "inputs": {
332
+ "input": { "dtype": "uint32", "shape": [3, 1], "data": { "kind": "values", "values": [0, 1, 0] } },
333
+ "shape": { "dtype": "uint32", "shape": [2], "data": { "kind": "values", "values": [1, 3] } }
334
+ },
335
+ "outputs": { "output": { "dtype": "uint32", "shape": [3, 3], "tolerance": 0 } }
336
+ },
337
+ {
338
+ "name": "ort_uint32_bool_row_to_rows",
339
+ "provenance": {
340
+ "source": "onnxruntime/test/providers/cpu/tensor/expand_test.cc",
341
+ "test": "ExpandOpTest.Expand_4x1_bool",
342
+ "notes": "Adapts ORT's bool tensor to logical uint32 values because this framework stores bool-like tensors as u32 slots."
343
+ },
344
+ "inputs": {
345
+ "input": { "dtype": "uint32", "shape": [1, 4], "data": { "kind": "values", "values": [0, 1, 0, 0] } },
346
+ "shape": { "dtype": "uint32", "shape": [2], "data": { "kind": "values", "values": [4, 1] } }
347
+ },
348
+ "outputs": { "output": { "dtype": "uint32", "shape": [4, 4], "tolerance": 0 } }
349
+ },
350
+ {
351
+ "name": "ort_scalar_float_empty_shape",
352
+ "provenance": {
353
+ "source": "onnxruntime/test/providers/cpu/tensor/expand_test.cc",
354
+ "test": "ExpandOpTest.Expand_scalar_float"
355
+ },
356
+ "inputs": {
357
+ "input": { "dtype": "float32", "shape": [], "data": { "kind": "values", "values": [3.0] } },
358
+ "shape": { "dtype": "uint32", "shape": [0], "data": { "kind": "values", "values": [] } }
359
+ },
360
+ "outputs": { "output": { "dtype": "float32", "shape": [], "tolerance": 0.000001 } }
361
+ },
362
+ {
363
+ "name": "onnx_backend_expand_dim_changed",
364
+ "inputs": {
365
+ "input": { "dtype": "float32", "shape": [3, 1], "data": { "kind": "values", "values": [1.0, 2.0, 3.0] } },
366
+ "shape": { "dtype": "uint32", "shape": [3], "data": { "kind": "values", "values": [2, 1, 6] } }
367
+ },
368
+ "outputs": { "output": { "dtype": "float32", "shape": [2, 3, 6] } },
369
+ "provenance": {
370
+ "source": "cmake/external/onnx/onnx/backend/test/data/node/test_expand_dim_changed",
371
+ "notes": "ONNX int64 metadata/index tensors use framework int32/uint32 slots where representable."
372
+ }
373
+ },
374
+ {
375
+ "name": "onnx_backend_expand_dim_unchanged",
376
+ "inputs": {
377
+ "input": { "dtype": "float32", "shape": [3, 1], "data": { "kind": "values", "values": [1.0, 2.0, 3.0] } },
378
+ "shape": { "dtype": "uint32", "shape": [2], "data": { "kind": "values", "values": [3, 4] } }
379
+ },
380
+ "outputs": { "output": { "dtype": "float32", "shape": [3, 4] } },
381
+ "provenance": {
382
+ "source": "cmake/external/onnx/onnx/backend/test/data/node/test_expand_dim_unchanged",
383
+ "notes": "ONNX int64 metadata/index tensors use framework int32/uint32 slots where representable."
384
+ }
385
+ },
386
+ {
387
+ "name": "ort_scalar_float_to_scalar",
388
+ "provenance": {
389
+ "source": "onnxruntime/test/providers/cpu/tensor/expand_test.cc",
390
+ "test": "ExpandOpTest.Expand_scalar_float",
391
+ "notes": "ORT shape is int64; this framework stores the empty shape tensor in uint32 slots."
392
+ },
393
+ "inputs": {
394
+ "input": { "dtype": "float32", "shape": [], "data": { "kind": "values", "values": [3.0] } },
395
+ "shape": { "dtype": "uint32", "shape": [0], "data": { "kind": "values", "values": [] } }
396
+ },
397
+ "outputs": { "output": { "dtype": "float32", "shape": [], "tolerance": 0 } }
398
+ },
399
+ {
400
+ "name": "ort_scalar_int32_to_rank3",
401
+ "provenance": {
402
+ "source": "onnxruntime/test/providers/cpu/tensor/expand_test.cc",
403
+ "test": "ExpandOpTest.Expand_scalar_int32",
404
+ "notes": "ORT shape is int64; this framework stores representable shape values in uint32 slots."
405
+ },
406
+ "inputs": {
407
+ "input": { "dtype": "int32", "shape": [], "data": { "kind": "values", "values": [9] } },
408
+ "shape": { "dtype": "uint32", "shape": [3], "data": { "kind": "values", "values": [2, 3, 4] } }
409
+ },
410
+ "outputs": { "output": { "dtype": "int32", "shape": [2, 3, 4], "tolerance": 0 } }
411
+ },
412
+ {
413
+ "name": "ort_bool_pattern_uint32_row_expand",
414
+ "provenance": {
415
+ "source": "onnxruntime/test/providers/cpu/tensor/expand_test.cc",
416
+ "test": "ExpandOpTest.Expand_3x1_bool",
417
+ "notes": "ORT uses bool payloads; this framework represents logical bool-like values as uint32 slots."
418
+ },
419
+ "inputs": {
420
+ "input": { "dtype": "uint32", "shape": [3], "data": { "kind": "values", "values": [0, 1, 0] } },
421
+ "shape": { "dtype": "uint32", "shape": [2], "data": { "kind": "values", "values": [3, 1] } }
422
+ },
423
+ "outputs": { "output": { "dtype": "uint32", "shape": [3, 3], "tolerance": 0 } }
424
+ },
425
+ {
426
+ "name": "ort_int8_vector_to_rows_edge_values",
427
+ "provenance": {
428
+ "source": "onnxruntime/test/providers/cpu/tensor/expand_test.cc",
429
+ "test": "ExpandOpTest.Expand_3x1_int32",
430
+ "notes": "Same row-broadcast shape as ORT's int32 case, using ONNX-valid signed byte edge values."
431
+ },
432
+ "inputs": {
433
+ "input": { "dtype": "int8", "shape": [3], "data": { "kind": "values", "values": [-128, -1, 127] } },
434
+ "shape": { "dtype": "uint32", "shape": [2], "data": { "kind": "values", "values": [3, 1] } }
435
+ },
436
+ "outputs": { "output": { "dtype": "int8", "shape": [3, 3], "tolerance": 0 } }
437
+ },
438
+ {
439
+ "name": "ort_uint8_col_vector_to_cols_edge_values",
440
+ "provenance": {
441
+ "source": "onnxruntime/test/providers/cpu/tensor/expand_test.cc",
442
+ "test": "ExpandOpTest.Expand_1x3_int32",
443
+ "notes": "Same column-broadcast shape as ORT's int32 case, using ONNX-valid unsigned byte edge values."
444
+ },
445
+ "inputs": {
446
+ "input": { "dtype": "uint8", "shape": [3, 1], "data": { "kind": "values", "values": [0, 128, 255] } },
447
+ "shape": { "dtype": "uint32", "shape": [2], "data": { "kind": "values", "values": [1, 3] } }
448
+ },
449
+ "outputs": { "output": { "dtype": "uint8", "shape": [3, 3], "tolerance": 0 } }
450
+ },
451
+ {
452
+ "name": "ort_bool_scalar_to_3x3",
453
+ "provenance": {
454
+ "source": "onnxruntime/test/providers/cpu/tensor/expand_test.cc",
455
+ "test": "ExpandOpTest.Expand_3x3_bool"
456
+ },
457
+ "inputs": {
458
+ "input": { "dtype": "bool", "shape": [1], "data": { "kind": "values", "values": [1] } },
459
+ "shape": { "dtype": "uint32", "shape": [2], "data": { "kind": "values", "values": [3, 3] } }
460
+ },
461
+ "outputs": {
462
+ "output": {
463
+ "dtype": "bool",
464
+ "shape": [3, 3],
465
+ "tolerance": 0,
466
+ "data": { "kind": "values", "values": [1, 1, 1, 1, 1, 1, 1, 1, 1] }
467
+ }
468
+ }
469
+ },
470
+ {
471
+ "name": "ort_bool_vector_to_rows",
472
+ "provenance": {
473
+ "source": "onnxruntime/test/providers/cpu/tensor/expand_test.cc",
474
+ "test": "ExpandOpTest.Expand_3x1_bool"
475
+ },
476
+ "inputs": {
477
+ "input": { "dtype": "bool", "shape": [3], "data": { "kind": "values", "values": [0, 1, 0] } },
478
+ "shape": { "dtype": "uint32", "shape": [2], "data": { "kind": "values", "values": [3, 1] } }
479
+ },
480
+ "outputs": {
481
+ "output": {
482
+ "dtype": "bool",
483
+ "shape": [3, 3],
484
+ "tolerance": 0,
485
+ "data": { "kind": "values", "values": [0, 1, 0, 0, 1, 0, 0, 1, 0] }
486
+ }
487
+ }
488
+ },
489
+ {
490
+ "name": "ort_bool_col_to_cols",
491
+ "provenance": {
492
+ "source": "onnxruntime/test/providers/cpu/tensor/expand_test.cc",
493
+ "test": "ExpandOpTest.Expand_1x3_bool",
494
+ "notes": "The requested shape has a leading dimension of 1; ONNX Expand keeps the input's leading dimension of 3 rather than shrinking it."
495
+ },
496
+ "inputs": {
497
+ "input": { "dtype": "bool", "shape": [3, 1], "data": { "kind": "values", "values": [0, 1, 0] } },
498
+ "shape": { "dtype": "uint32", "shape": [2], "data": { "kind": "values", "values": [1, 3] } }
499
+ },
500
+ "outputs": {
501
+ "output": {
502
+ "dtype": "bool",
503
+ "shape": [3, 3],
504
+ "tolerance": 0,
505
+ "data": { "kind": "values", "values": [0, 0, 0, 1, 1, 1, 0, 0, 0] }
506
+ }
507
+ }
508
+ },
509
+ {
510
+ "name": "ort_bool_row_to_four_rows",
511
+ "provenance": {
512
+ "source": "onnxruntime/test/providers/cpu/tensor/expand_test.cc",
513
+ "test": "ExpandOpTest.Expand_4x1_bool"
514
+ },
515
+ "inputs": {
516
+ "input": { "dtype": "bool", "shape": [1, 4], "data": { "kind": "values", "values": [0, 1, 0, 0] } },
517
+ "shape": { "dtype": "uint32", "shape": [2], "data": { "kind": "values", "values": [4, 1] } }
518
+ },
519
+ "outputs": {
520
+ "output": {
521
+ "dtype": "bool",
522
+ "shape": [4, 4],
523
+ "tolerance": 0,
524
+ "data": { "kind": "values", "values": [0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0] }
525
+ }
526
+ }
527
+ },
528
+ {
529
+ "name": "int8_vec4_path_edge_values",
530
+ "inputs": {
531
+ "input": { "dtype": "int8", "shape": [1, 4], "data": { "kind": "values", "values": [-128, -1, 0, 127] } },
532
+ "shape": { "dtype": "uint32", "shape": [2], "data": { "kind": "values", "values": [3, 4] } }
533
+ },
534
+ "outputs": { "output": { "dtype": "int8", "shape": [3, 4], "tolerance": 0 } }
535
+ },
536
+ {
537
+ "name": "uint8_vec4_path_broadcast_row",
538
+ "inputs": {
539
+ "input": {
540
+ "dtype": "uint8",
541
+ "shape": [1, 8],
542
+ "data": { "kind": "values", "values": [0, 64, 128, 192, 255, 1, 127, 254] }
543
+ },
544
+ "shape": { "dtype": "uint32", "shape": [2], "data": { "kind": "values", "values": [4, 8] } }
545
+ },
546
+ "outputs": { "output": { "dtype": "uint8", "shape": [4, 8], "tolerance": 0 } }
547
+ },
548
+ {
549
+ "name": "rank7_vec4_last_dim_divisible",
550
+ "inputs": {
551
+ "input": {
552
+ "dtype": "float32",
553
+ "shape": [2, 1, 3, 1, 2, 1, 4],
554
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.19 }
555
+ },
556
+ "shape": { "dtype": "uint32", "shape": [7], "data": { "kind": "values", "values": [2, 3, 3, 2, 2, 2, 4] } }
557
+ },
558
+ "outputs": { "output": { "dtype": "float32", "shape": [2, 3, 3, 2, 2, 2, 4], "tolerance": 0.000001 } }
559
+ },
560
+ {
561
+ "name": "rank8_broadcast",
562
+ "inputs": {
563
+ "input": {
564
+ "dtype": "float32",
565
+ "shape": [1, 2, 1, 3, 1, 1, 2, 1],
566
+ "data": { "kind": "fillFloat32", "sinStep": 0.07, "cosStep": 0.19 }
567
+ },
568
+ "shape": { "dtype": "uint32", "shape": [8], "data": { "kind": "values", "values": [2, 2, 4, 3, 2, 3, 2, 2] } }
569
+ },
570
+ "outputs": { "output": { "dtype": "float32", "shape": [2, 2, 4, 3, 2, 3, 2, 2], "tolerance": 0.000001 } }
571
+ },
572
+ {
573
+ "name": "f16_vec4_row_broadcast",
574
+ "provenance": {
575
+ "source": "authored for render coverage",
576
+ "test": "expand-vec4 `usesF16` arm",
577
+ "notes": "A float16 output whose innermost dimension is four exercises vec4 broadcasting and half-precision storage. Expand only copies exactly representable values, so the expected output is exact at tolerance zero."
578
+ },
579
+ "inputs": {
580
+ "input": {
581
+ "dtype": "float16",
582
+ "shape": [1, 8],
583
+ "data": { "kind": "values", "values": [1.0, -2.0, 3.5, -4.25, 8.0, -16.5, 0.125, 64.0] }
584
+ },
585
+ "shape": { "dtype": "uint32", "shape": [2], "data": { "kind": "values", "values": [3, 8] } }
586
+ },
587
+ "outputs": { "output": { "dtype": "float16", "shape": [3, 8], "tolerance": 0 } }
588
+ },
589
+ {
590
+ "name": "same_shape_identity_vec4",
591
+ "provenance": {
592
+ "source": "authored for render coverage",
593
+ "test": "expand-vec4 `x_same` arm",
594
+ "notes": "The requested shape equals the input shape, so expand-vec4 takes the x_same branch and emits the identity offset `return out_index;` instead of including expand-broadcast-offset. No other case has an input shape identical to the output shape while the innermost dim is divisible by 4; every other vec4-eligible case broadcasts at least one axis. All eight values are distinct so a wrong offset in the identity path shows up per position."
595
+ },
596
+ "inputs": {
597
+ "input": {
598
+ "dtype": "float32",
599
+ "shape": [2, 4],
600
+ "data": { "kind": "values", "values": [1.0, -2.0, 3.0, -4.0, 5.0, -6.0, 7.0, -8.0] }
601
+ },
602
+ "shape": { "dtype": "uint32", "shape": [2], "data": { "kind": "values", "values": [2, 4] } }
603
+ },
604
+ "outputs": { "output": { "dtype": "float32", "shape": [2, 4], "tolerance": 0 } }
605
+ }
606
+ ]
607
+ }