@thi.ng/tensors 0.6.4 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Change Log
2
2
 
3
- - **Last updated**: 2025-06-24T21:39:38Z
3
+ - **Last updated**: 2025-07-10T14:20:23Z
4
4
  - **Generator**: [thi.ng/monopub](https://thi.ng/monopub)
5
5
 
6
6
  All notable changes to this project will be documented in this file.
@@ -11,6 +11,24 @@ See [Conventional Commits](https://conventionalcommits.org/) for commit guidelin
11
11
  **Note:** Unlisted _patch_ versions only involve non-code or otherwise excluded changes
12
12
  and/or version bumps of transitive dependencies.
13
13
 
14
+ ## [0.8.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/tensors@0.8.0) (2025-07-10)
15
+
16
+ #### 🚀 Features
17
+
18
+ - add `step()`/`smoothStep()` variations ([b433462](https://github.com/thi-ng/umbrella/commit/b433462))
19
+ - add ITensor.crop() ([77e294d](https://github.com/thi-ng/umbrella/commit/77e294d))
20
+
21
+ ## [0.7.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/tensors@0.7.0) (2025-07-09)
22
+
23
+ #### 🚀 Features
24
+
25
+ - add `integrate()` tensor op ([fe39a4a](https://github.com/thi-ng/umbrella/commit/fe39a4a))
26
+ - add `TensorLike` and `asTensor()` ([f76d9a6](https://github.com/thi-ng/umbrella/commit/f76d9a6))
27
+
28
+ #### ♻️ Refactoring
29
+
30
+ - migrate `asTensor()` to convert.ts ([fcb83c5](https://github.com/thi-ng/umbrella/commit/fcb83c5))
31
+
14
32
  ## [0.6.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/tensors@0.6.0) (2025-06-05)
15
33
 
16
34
  #### 🚀 Features
package/README.md CHANGED
@@ -40,6 +40,24 @@
40
40
 
41
41
  ## Built-in tensor operations
42
42
 
43
+ The [`ITensor`
44
+ interface](https://docs.thi.ng/umbrella/tensors/interfaces/ITensor.html) shared
45
+ by all tensor implementations provides the following methods (non-exhaustive
46
+ list here):
47
+
48
+ - [.crop(pos, size)](https://docs.thi.ng/umbrella/tensors/interfaces/ITensor.html#get-1): Crop tensor region (zero copy)
49
+ - [.get(pos)](https://docs.thi.ng/umbrella/tensors/interfaces/ITensor.html#get-1): Get value at position
50
+ - [.hi(pos)](https://docs.thi.ng/umbrella/tensors/interfaces/ITensor.html#hi-1): Crop tensor (high end, zero copy)
51
+ - [.index(pos)](https://docs.thi.ng/umbrella/tensors/interfaces/ITensor.html#index-1): Get index for position
52
+ - [.lo(pos)](https://docs.thi.ng/umbrella/tensors/interfaces/ITensor.html#lo-1): Crop tensor (low end, zero copy)
53
+ - [.pack(storage?)](https://docs.thi.ng/umbrella/tensors/interfaces/ITensor.html#pack-1): Copy tensor with data tightly packed
54
+ - [.pick(axes)](https://docs.thi.ng/umbrella/tensors/interfaces/ITensor.html#pick-1): Select axes only (zero copy)
55
+ - [.position(index)](https://docs.thi.ng/umbrella/tensors/interfaces/ITensor.html#position-1): Get position for index
56
+ - [.reshape(newShape, newStride?)](https://docs.thi.ng/umbrella/tensors/interfaces/ITensor.html#reshape-1): Reshape tensor (zero copy)
57
+ - [.set(pos)](https://docs.thi.ng/umbrella/tensors/interfaces/ITensor.html#set-1): Set value at position
58
+ - [.step(axes)](https://docs.thi.ng/umbrella/tensors/interfaces/ITensor.html#step-1): Skip axes (zero copy)
59
+ - [.transpose(order)](https://docs.thi.ng/umbrella/tensors/interfaces/ITensor.html#transpose-1): Re-order axes (zero copy)
60
+
43
61
  The set of tensor polymorphic component-wise ops is easily extensible via
44
62
  provided higher-order functions in the `defOpXX()` family. Most of the ops
45
63
  listed below are also based on this approach. The function signatures and naming
@@ -49,53 +67,66 @@ conventions are closely aligned to the ones used by the
49
67
  - [abs](https://docs.thi.ng/umbrella/tensors/variables/abs.html): Componentwise `Math.abs`
50
68
  - [add](https://docs.thi.ng/umbrella/tensors/variables/add.html): Tensor-tensor addition
51
69
  - [addN](https://docs.thi.ng/umbrella/tensors/variables/addN.html): Tensor-scalar addition
52
- - [argMax](https://docs.thi.ng/umbrella/tensors/variables/argMax.html): Maximum component index/value
53
- - [argMin](https://docs.thi.ng/umbrella/tensors/variables/argMin.html): Minimum component index/value
70
+ - [argMax](https://docs.thi.ng/umbrella/tensors/functions/argMax.html): Maximum component index/value
71
+ - [argMin](https://docs.thi.ng/umbrella/tensors/functions/argMin.html): Minimum component index/value
54
72
  - [clamp](https://docs.thi.ng/umbrella/tensors/variables/clamp.html): Tensor-tensor interval clamping
55
73
  - [clampN](https://docs.thi.ng/umbrella/tensors/variables/clampN.html): Tensor-scalar interval clamping
56
74
  - [convolve](https://docs.thi.ng/umbrella/tensors/variables/convolve.html): Tensor convolution (1D/2D/3D only)
57
75
  - [cos](https://docs.thi.ng/umbrella/tensors/variables/cos.html): Componentwise `Math.cos`
58
- - [diagonal](https://docs.thi.ng/umbrella/tensors/variables/diagonal.html): Diagonal extraction
76
+ - [diagonal](https://docs.thi.ng/umbrella/tensors/functions/diagonal.html): Diagonal extraction
59
77
  - [div](https://docs.thi.ng/umbrella/tensors/variables/div.html): Tensor-tensor division
60
78
  - [divN](https://docs.thi.ng/umbrella/tensors/variables/divN.html): Tensor-scalar division
61
79
  - [dot](https://docs.thi.ng/umbrella/tensors/variables/dot.html): Dot product
62
80
  - [exp](https://docs.thi.ng/umbrella/tensors/variables/exp.html): Componentwise `Math.exp`
63
81
  - [exp2](https://docs.thi.ng/umbrella/tensors/variables/exp2.html): Componentwise `2^x`
82
+ - [identity](https://docs.thi.ng/umbrella/tensors/functions/identity.html): Square identity matrix tensor
83
+ - [integrate](https://docs.thi.ng/umbrella/tensors/functions/integrate.html): Integrate tensor along innermost dimension
64
84
  - [log](https://docs.thi.ng/umbrella/tensors/variables/log.html): Componentwise `Math.log`
65
85
  - [log2](https://docs.thi.ng/umbrella/tensors/variables/log2.html): Componentwise `Math.log2`
66
- - [mag](https://docs.thi.ng/umbrella/tensors/variables/mag.html): Tensor magnitude
86
+ - [mag](https://docs.thi.ng/umbrella/tensors/functions/mag.html): Tensor magnitude
67
87
  - [magSq](https://docs.thi.ng/umbrella/tensors/variables/magSq.html): Tensor squared magnitude
68
88
  - [max](https://docs.thi.ng/umbrella/tensors/variables/max.html): Tensor-tensor maximum
69
89
  - [maxN](https://docs.thi.ng/umbrella/tensors/variables/maxN.html): Tensor-scalar maximum
70
- - [min](https://docs.thi.ng/umbrella/tensors/variables/min.html): Tensor-tensor minimum
90
+ - [mean](https://docs.thi.ng/umbrella/tensors/functions/mean.html): Tensor mean value
91
+ - [min](https://docs.thi.ng/umbrella/tensors/functions/min.html): Tensor-tensor minimum
71
92
  - [minN](https://docs.thi.ng/umbrella/tensors/variables/minN.html): Tensor-scalar maximum
72
93
  - [mul](https://docs.thi.ng/umbrella/tensors/variables/mul.html): Tensor-tensor multiplication
73
94
  - [mulN](https://docs.thi.ng/umbrella/tensors/variables/mulN.html): Tensor-scalar multiplication
74
- - [mulM](https://docs.thi.ng/umbrella/tensors/variables/mulM.html): Matrix-matrix product
75
- - [mulV](https://docs.thi.ng/umbrella/tensors/variables/mulV.html): Matrix-vector product
76
- - [normalize](https://docs.thi.ng/umbrella/tensors/variables/normalize.html): Tensor normalization (w/ optional length)
95
+ - [mulM](https://docs.thi.ng/umbrella/tensors/functions/mulM.html): Matrix-matrix product
96
+ - [mulV](https://docs.thi.ng/umbrella/tensors/functions/mulV.html): Matrix-vector product
97
+ - [negativeIndices](https://docs.thi.ng/umbrella/tensors/variables/negativeIndices.html): Indices of negative component values
98
+ - [nonZeroIndices](https://docs.thi.ng/umbrella/tensors/variables/nonZeroIndices.html): Indices of non-zero component values
99
+ - [normalize](https://docs.thi.ng/umbrella/tensors/functions/normalize.html): Tensor normalization (w/ optional length)
100
+ - [ones](https://docs.thi.ng/umbrella/tensors/functions/ones.html): One-filled tensor creation
101
+ - [positiveIndices](https://docs.thi.ng/umbrella/tensors/variables/positiveIndices.html): Indices of positive component values
77
102
  - [pow](https://docs.thi.ng/umbrella/tensors/variables/pow.html): Tensor-tensor `Math.pow`
78
103
  - [powN](https://docs.thi.ng/umbrella/tensors/variables/powN.html): Tensor-scalar `Math.pow`
104
+ - [print](https://docs.thi.ng/umbrella/tensors/functions/print.html): Formatted tensor output
79
105
  - [product](https://docs.thi.ng/umbrella/tensors/variables/product.html): Component product
80
106
  - [randDistrib](https://docs.thi.ng/umbrella/tensors/variables/randDistrib.html): Fill with random data from distribution fn
81
- - [range](https://docs.thi.ng/umbrella/tensors/variables/range.html): Create 1D tensor of monotonically increasing/decreasing values
107
+ - [range](https://docs.thi.ng/umbrella/tensors/functions/range.html): Create 1D tensor of monotonically increasing/decreasing values
82
108
  - [relu](https://docs.thi.ng/umbrella/tensors/variables/relu.html): ReLU activation
83
109
  - [reluN](https://docs.thi.ng/umbrella/tensors/variables/reluN.html): Leaky ReLU activation
84
- - [select](https://docs.thi.ng/umbrella/tensors/variables/select.html): Generalization of argMin/Max
85
- - [set](https://docs.thi.ng/umbrella/tensors/variables/set.html): Tensor setter
86
- - [setN](https://docs.thi.ng/umbrella/tensors/variables/setN.html): Tensor setter w/ uniform scalar
110
+ - [select](https://docs.thi.ng/umbrella/tensors/functions/select.html): Generalization of argMin/Max
111
+ - [set](https://docs.thi.ng/umbrella/tensors/functions/set.html): Tensor setter
112
+ - [setN](https://docs.thi.ng/umbrella/tensors/functions/setN.html): Tensor setter w/ uniform scalar
87
113
  - [sigmoid](https://docs.thi.ng/umbrella/tensors/variables/sigmoid.html): Sigmoid activation
88
114
  - [sin](https://docs.thi.ng/umbrella/tensors/variables/sin.html): Componentwise `Math.sin`
89
- - [softMax](https://docs.thi.ng/umbrella/tensors/variables/softMax.html): Soft Max activation
115
+ - [smoothStep](https://docs.thi.ng/umbrella/tensors/variables/smoothStep.html): Smooth threshold function (as as GLSL `smoothstep()`)
116
+ - [smoothStepN](https://docs.thi.ng/umbrella/tensors/variables/smoothStepN.html): Smooth threshold function (as as GLSL `smoothstep()`)
117
+ - [softMax](https://docs.thi.ng/umbrella/tensors/functions/softMax.html): Soft Max activation
90
118
  - [sqrt](https://docs.thi.ng/umbrella/tensors/variables/sqrt.html): Componentwise `Math.sqrt`
91
119
  - [step](https://docs.thi.ng/umbrella/tensors/variables/step.html): Threshold function (as as GLSL `step()`)
120
+ - [stepN](https://docs.thi.ng/umbrella/tensors/variables/stepN.html): Threshold function (as as GLSL `step()`)
92
121
  - [sub](https://docs.thi.ng/umbrella/tensors/variables/sub.html): Tensor-tensor subtraction
93
122
  - [subN](https://docs.thi.ng/umbrella/tensors/variables/subN.html): Tensor-scalar subtraction
94
123
  - [sum](https://docs.thi.ng/umbrella/tensors/variables/sum.html): Component sum
95
- - [svd](https://docs.thi.ng/umbrella/tensors/variables/sum.html): Singular value decomposition
124
+ - [svd](https://docs.thi.ng/umbrella/tensors/functions/svd.html): Singular value decomposition
125
+ - [swap](https://docs.thi.ng/umbrella/tensors/functions/swap.html): Swap tensor values
96
126
  - [tan](https://docs.thi.ng/umbrella/tensors/variables/tan.html): Componentwise `Math.tan`
97
127
  - [tanh](https://docs.thi.ng/umbrella/tensors/variables/tanh.html): Componentwise `Math.tanh`
98
- - [trace](https://docs.thi.ng/umbrella/tensors/variables/trace.html): Matrix trace (diagonal component sum)
128
+ - [trace](https://docs.thi.ng/umbrella/tensors/functions/trace.html): Matrix trace (diagonal component sum)
129
+ - [zeroes](https://docs.thi.ng/umbrella/tensors/functions/zeroes.html): Zero-filled tensor creation
99
130
 
100
131
  ### Broadcasting support
101
132
 
@@ -182,6 +213,8 @@ factories can be used with
182
213
  The following functions can be used to convert/coerce other data structures into
183
214
  tensors:
184
215
 
216
+ - [`asTensor()`](https://docs.thi.ng/umbrella/tensors/functions/asTensor.html):
217
+ Convert/wrap data as tensor
185
218
  - [`fromFloatBuffer()`](https://docs.thi.ng/umbrella/tensors/functions/fromFloatBuffer.html):
186
219
  Coerce [thi.ng/pixel] float buffer/image (or compatible data structures) into
187
220
  a 2D/3D tensor
@@ -218,7 +251,7 @@ For Node.js REPL:
218
251
  const ten = await import("@thi.ng/tensors");
219
252
  ```
220
253
 
221
- Package sizes (brotli'd, pre-treeshake): ESM: 9.48 KB
254
+ Package sizes (brotli'd, pre-treeshake): ESM: 9.75 KB
222
255
 
223
256
  ## Dependencies
224
257
 
package/api.d.ts CHANGED
@@ -58,6 +58,21 @@ export interface TensorFromArrayOpts<T extends Type, V> {
58
58
  type: T;
59
59
  storage?: ITensorStorage<V>;
60
60
  }
61
+ /**
62
+ * Source data type for tensor conversion via {@link asTensor}.
63
+ */
64
+ export interface TensorLike<T extends Type, S extends Shape> {
65
+ /** Data type */
66
+ type: T;
67
+ /** Tensor data/values (MUST match `type`) */
68
+ data: TensorData<TypeMap[T]>;
69
+ /** Tensor shape */
70
+ shape: S;
71
+ /** Stride/layout information of data */
72
+ stride: S;
73
+ /** Start index (default: 0) */
74
+ offset?: number;
75
+ }
61
76
  export interface ITensor<T = number> extends ICopy<ITensor<T>>, IEquiv, IEqualsDelta<ITensor<T>>, IRelease {
62
77
  readonly type: Type;
63
78
  readonly storage: ITensorStorage<T>;
@@ -81,6 +96,13 @@ export interface ITensor<T = number> extends ICopy<ITensor<T>>, IEquiv, IEqualsD
81
96
  * @internal
82
97
  */
83
98
  broadcast<S extends Shape>(shape: S, stride: S): ShapeTensor<S, T>;
99
+ /**
100
+ * Returns a new tensor of same shape, but all values zeroed. Unless
101
+ * `storage` is given, the new data will be allocated using this tensor's
102
+ * storage provider.
103
+ *
104
+ * @param storage
105
+ */
84
106
  empty(storage?: ITensorStorage<T>): this;
85
107
  /**
86
108
  * Computes linear array index from given grid position. Reverse-op of
@@ -102,15 +124,286 @@ export interface ITensor<T = number> extends ICopy<ITensor<T>>, IEquiv, IEqualsD
102
124
  * @param index
103
125
  */
104
126
  position(index: number): number[];
127
+ /**
128
+ * Returns value at given grid position. No bounds checking.
129
+ *
130
+ * @param pos
131
+ */
105
132
  get(pos: NumericArray): T;
133
+ /**
134
+ * Sets value at given grid position. No bounds checking.
135
+ *
136
+ * @param pos
137
+ * @param value
138
+ */
106
139
  set(pos: NumericArray, value: T): this;
140
+ /**
141
+ * Returns a new tensor of the bottom-right region starting from given
142
+ * `pos`. View transform only, no data will be copied.
143
+ *
144
+ * @remarks
145
+ * Also see {@link Itensor.hi}, {@link ITensor.crop}.
146
+ *
147
+ * @example
148
+ * ```ts tangle:../export/itensor-lo.ts
149
+ * import { print, range } from "@thi.ng/tensors";
150
+ *
151
+ * const a = range(16).reshape([4, 4]);
152
+ * print(a);
153
+ * // 0 1.0000 2.0000 3.0000
154
+ * // 4.0000 5.0000 6.0000 7.0000
155
+ * // 8.0000 9.0000 10.0000 11.0000
156
+ * // 12.0000 13.0000 14.0000 15.0000
157
+ *
158
+ * const b = a.lo([2, 1]);
159
+ * print(b);
160
+ * // 9.0000 10.0000 11.0000
161
+ * // 13.0000 14.0000 15.0000
162
+ * ```
163
+ *
164
+ * @param pos
165
+ */
107
166
  lo(pos: NumericArray): this;
167
+ /**
168
+ * Returns a new tensor of the top-left region until given `pos` (excluded).
169
+ * View transform only, no data will be copied.
170
+ *
171
+ * @remarks
172
+ * Also see {@link Itensor.lo}, {@link ITensor.crop}.
173
+ *
174
+ * @example
175
+ * ```ts tangle:../export/itensor-hi.ts
176
+ * import { print, range } from "@thi.ng/tensors";
177
+ *
178
+ * const a = range(16).reshape([4, 4]);
179
+ * print(a);
180
+ * // 0 1.0000 2.0000 3.0000
181
+ * // 4.0000 5.0000 6.0000 7.0000
182
+ * // 8.0000 9.0000 10.0000 11.0000
183
+ * // 12.0000 13.0000 14.0000 15.0000
184
+ *
185
+ * const b = a.hi([2, 3]);
186
+ * print(b);
187
+ * // 0 1.0000 2.0000
188
+ * // 4.0000 5.0000 6.0000
189
+ * ```
190
+ *
191
+ * @param pos
192
+ */
108
193
  hi(pos: NumericArray): this;
194
+ /**
195
+ * Returns a new tensor of the extracted region defined by `pos` and `size`.
196
+ * This op is a combination of {@link ITensor.lo} and {@link ITensor.hi}.
197
+ * View transform only, no data will be copied.
198
+ *
199
+ * @example
200
+ * ```ts tangle:../export/itensor-crop.ts
201
+ * import { print, range } from "@thi.ng/tensors";
202
+ *
203
+ * const a = range(16).reshape([4, 4]);
204
+ * print(a);
205
+ * // 0 1.0000 2.0000 3.0000
206
+ * // 4.0000 5.0000 6.0000 7.0000
207
+ * // 8.0000 9.0000 10.0000 11.0000
208
+ * // 12.0000 13.0000 14.0000 15.0000
209
+ *
210
+ * const b = a.crop([1, 1], [2, 2]);
211
+ * print(b);
212
+ * // 5.0000 6.0000
213
+ * // 9.0000 10.0000
214
+ * ```
215
+ *
216
+ * @param pos
217
+ * @param size
218
+ */
219
+ crop(pos: NumericArray, size: NumericArray): this;
220
+ /**
221
+ * Returns a new tensor with step sizes adjusted for selected axes (Using
222
+ * zero for an axis will keep its current step size). View transform only,
223
+ * no data will be copied.
224
+ *
225
+ * @example
226
+ * ```ts tangle:../export/itensor-step.ts
227
+ * import { print, range } from "@thi.ng/tensors";
228
+ *
229
+ * const a = range(16).reshape([4, 4]);
230
+ * print(a);
231
+ * // 0 1.0000 2.0000 3.0000
232
+ * // 4.0000 5.0000 6.0000 7.0000
233
+ * // 8.0000 9.0000 10.0000 11.0000
234
+ * // 12.0000 13.0000 14.0000 15.0000
235
+ *
236
+ * // only select every 2nd row
237
+ * const b = a.step([2, 1]);
238
+ * print(b);
239
+ * // 0 1.0000 2.0000 3.0000
240
+ * // 8.0000 9.0000 10.0000 11.0000
241
+ *
242
+ * // keep rows as is (zero), only select every 2nd column
243
+ * print(b.step([0, 2]));
244
+ * // 0 2.0000
245
+ * // 8.0000 10.0000
246
+ * ```
247
+ *
248
+ * @param select
249
+ */
109
250
  step(select: NumericArray): this;
251
+ /**
252
+ * Returns a new tensor with only the `select`ed axes. A -1 will select all
253
+ * value in that axis. View transform only, no data will be copied.
254
+ *
255
+ * @example
256
+ * ```ts tangle:../export/itensor-pick.ts
257
+ * import { print, range } from "@thi.ng/tensors";
258
+ *
259
+ * // 3D 4x4x4 tensor with values in [0,64) range
260
+ * const a = range(64).reshape([4, 4, 4]);
261
+ *
262
+ * // pick entire slice #2
263
+ * print(a.pick([2]));
264
+ * // 32.0000 33.0000 34.0000 35.0000
265
+ * // 36.0000 37.0000 38.0000 39.0000
266
+ * // 40.0000 41.0000 42.0000 43.0000
267
+ * // 44.0000 45.0000 46.0000 47.0000
268
+ *
269
+ * // pick slice #2, row #2 (1D tensor)
270
+ * print(a.pick([2, 2]));
271
+ * // 40.0000 41.0000 42.0000 43.0000
272
+ *
273
+ * // pick slice #2, column #2 (1D tensor)
274
+ * print(a.pick([2, -1, 2]));
275
+ * // 34.0000 38.0000 42.0000 46.0000
276
+ * ```
277
+ *
278
+ * @param select
279
+ */
110
280
  pick(select: NumericArray): ITensor<T>;
281
+ /**
282
+ * Creates a "packed" copy of this tensor with dense striding and the new
283
+ * data array only holding the values actually referenced by this tensor.
284
+ * Unless `storage` is given, the new data will be allocated using this
285
+ * tensor's storage provider.
286
+ *
287
+ * @remarks
288
+ * Since most other `ITensor` ops are zero-copy, view-only transforms, often
289
+ * resulting in "sparse" views which are only addressing a subset of the
290
+ * values stored, using `.pack()` is useful to extract data into a dense
291
+ * tensor/buffer.
292
+ *
293
+ * @example
294
+ * ```ts tangle:../export/itensor-pack.ts
295
+ * import { range } from "@thi.ng/tensors";
296
+ *
297
+ * const a = range(16).reshape([4, 4]);
298
+ * console.log("a data", a.data);
299
+ * // a data [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ]
300
+ *
301
+ * // only select every 2nd row & column
302
+ * const b = a.step([2, 2]);
303
+ * console.log("b values", [...b]);
304
+ * // b values [ 0, 2, 8, 10 ]
305
+ * console.log("b data", b.data);
306
+ * // b data [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ]
307
+ *
308
+ * // create packed version of `b`
309
+ * const c = b.pack();
310
+ * console.log("c data", c.data);
311
+ * // c data [ 0, 2, 8, 10 ]
312
+ * ```
313
+ *
314
+ * @param storage
315
+ */
111
316
  pack(storage?: ITensorStorage<T>): this;
317
+ /**
318
+ * Returns a new tensor with same data but given new shape (and optionally
319
+ * new strides). The total number of elements of the new shape MUST match
320
+ * that of the current shape (otherwise an error will be thrown).
321
+ *
322
+ * @remarks
323
+ * Also see {@link ITensor.crop} and {@link ITensor.resize}
324
+ *
325
+ * @example
326
+ * ```ts tangle:../export/itensor-reshape.ts
327
+ * import { print, range } from "@thi.ng/tensors";
328
+ *
329
+ * // 1D tensor
330
+ * const a = range(16);
331
+ *
332
+ * // reshape as 2D tensor
333
+ * print(a.reshape([4, 4]));
334
+ * // 0 1.0000 2.0000 3.0000
335
+ * // 4.0000 5.0000 6.0000 7.0000
336
+ * // 8.0000 9.0000 10.0000 11.0000
337
+ * // 12.0000 13.0000 14.0000 15.0000
338
+ *
339
+ * // reshape as 3D tensor
340
+ * print(a.reshape([2, 2, 4]));
341
+ * // --- 0: ---
342
+ * // 0 1.0000 2.0000 3.0000
343
+ * // 4.0000 5.0000 6.0000 7.0000
344
+ * // --- 1: ---
345
+ * // 8.0000 9.0000 10.0000 11.0000
346
+ * // 12.0000 13.0000 14.0000 15.0000
347
+ * ```
348
+ *
349
+ * @param newShape
350
+ * @param newStride
351
+ */
112
352
  reshape<S extends Shape>(newShape: S, newStride?: S): ShapeTensor<S, T>;
353
+ /**
354
+ * Returns a copy of the tensor resized to `newShape`. If the new shape is
355
+ * larger than the current shape, the extra data values will be initialized
356
+ * to `fill` (default: zero). Values will be copied in current iteration
357
+ * order (same logic as numpy). Unless `storage` is given, the new data will
358
+ * be allocated using this tensor's storage provider.
359
+ *
360
+ * @remarks
361
+ * Also see {@link ITensor.crop}, {@link ITensor.reshape}.
362
+ *
363
+ * @example
364
+ * ```ts tangle:../export/itensor-resize.ts
365
+ * import { print, range } from "@thi.ng/tensors";
366
+ *
367
+ * // 2D 4x4 tensor with values in [0,16) range
368
+ * const a = range(16).reshape([4, 4]);
369
+ *
370
+ * print(a.resize([4, 8]));
371
+ * // 0 1.0000 2.0000 3.0000 4.0000 5.0000 6.0000 7.0000
372
+ * // 8.0000 9.0000 10.0000 11.0000 12.0000 13.0000 14.0000 15.0000
373
+ * // 0 0 0 0 0 0 0 0
374
+ * // 0 0 0 0 0 0 0 0
375
+ * ```
376
+ *
377
+ * @param newShape
378
+ * @param fill
379
+ * @param storage
380
+ */
113
381
  resize<S extends Shape>(newShape: S, fill?: T, storage?: ITensorStorage<T>): ShapeTensor<S, T>;
382
+ /**
383
+ * Returns a new tensor with the given new axis `order`. View transform
384
+ * only, no data will be copied.
385
+ *
386
+ * @example
387
+ * ```ts tangle:../export/itensor-transpose.ts
388
+ * import { print, range } from "@thi.ng/tensors";
389
+ *
390
+ * const a = range(12).reshape([3, 4]);
391
+ * print(a);
392
+ * // 0 1.0000 2.0000 3.0000
393
+ * // 4.0000 5.0000 6.0000 7.0000
394
+ * // 8.0000 9.0000 10.0000 11.0000
395
+ *
396
+ * // swap row & column order
397
+ * const b = a.transpose([1, 0]);
398
+ * print(b);
399
+ * // 0 4.0000 8.0000
400
+ * // 1.0000 5.0000 9.0000
401
+ * // 2.0000 6.0000 10.0000
402
+ * // 3.0000 7.0000 11.0000
403
+ * ```
404
+ *
405
+ * @param order
406
+ */
114
407
  transpose(order: NumericArray): this;
115
408
  toJSON(): any;
116
409
  }
package/convert.d.ts CHANGED
@@ -1,4 +1,29 @@
1
1
  import type { NumericArray } from "@thi.ng/api";
2
+ import type { Shape, ShapeTensor, TensorLike, TensorOpts, Type, TypeMap } from "./api.js";
3
+ /**
4
+ * Converts/wraps given {@link TensorLike} `src` into a matching tensor
5
+ * implementation. By default the source data is NOT copied.
6
+ *
7
+ * @example
8
+ * ```ts tangle:../export/as-tensor.ts
9
+ * import { asTensor, print } from "@thi.ng/tensors";
10
+ *
11
+ * const src = {
12
+ * data: [1, 2, 3, 4],
13
+ * type: <const>"num",
14
+ * shape: <[number,number]>[2, 2],
15
+ * stride: <[number,number]>[2, 1],
16
+ * };
17
+ *
18
+ * print(asTensor(src));
19
+ * // 1.0000 2.0000
20
+ * // 3.0000 4.0000
21
+ * ```
22
+ *
23
+ * @param src
24
+ * @param opts
25
+ */
26
+ export declare const asTensor: <T extends Type, S extends Shape>(src: TensorLike<T, S>, opts?: Pick<TensorOpts<TypeMap[T], S>, "storage" | "copy">) => ShapeTensor<S, TypeMap[T]>;
2
27
  /**
3
28
  * Simplified interface of thi.ng/pixel `FloatBuffer`, only defining parts
4
29
  * relevant to the conversion.
package/convert.js CHANGED
@@ -1,5 +1,12 @@
1
1
  import { typedArrayType } from "@thi.ng/api/typedarray";
2
2
  import { tensor } from "./tensor.js";
3
+ const asTensor = (src, opts) => tensor(src.type, src.shape, {
4
+ copy: false,
5
+ data: src.data,
6
+ stride: src.stride,
7
+ offset: src.offset,
8
+ ...opts
9
+ });
3
10
  const fromFloatBuffer = ({
4
11
  size: [sx, sy],
5
12
  stride: [tx, ty],
@@ -18,5 +25,6 @@ const fromFloatBuffer = ({
18
25
  });
19
26
  };
20
27
  export {
28
+ asTensor,
21
29
  fromFloatBuffer
22
30
  };
package/index.d.ts CHANGED
@@ -27,6 +27,7 @@ export * from "./exp2.js";
27
27
  export * from "./filtered-indices.js";
28
28
  export * from "./format.js";
29
29
  export * from "./identity.js";
30
+ export * from "./integrate.js";
30
31
  export * from "./kernels.js";
31
32
  export * from "./log.js";
32
33
  export * from "./log2.js";
@@ -54,10 +55,13 @@ export * from "./set.js";
54
55
  export * from "./setn.js";
55
56
  export * from "./sigmoid.js";
56
57
  export * from "./sin.js";
58
+ export * from "./smoothstep.js";
59
+ export * from "./smoothstepn.js";
57
60
  export * from "./softmax.js";
58
61
  export * from "./softplus.js";
59
62
  export * from "./sqrt.js";
60
63
  export * from "./step.js";
64
+ export * from "./stepn.js";
61
65
  export * from "./storage.js";
62
66
  export * from "./sub.js";
63
67
  export * from "./subn.js";
package/index.js CHANGED
@@ -27,6 +27,7 @@ export * from "./exp2.js";
27
27
  export * from "./filtered-indices.js";
28
28
  export * from "./format.js";
29
29
  export * from "./identity.js";
30
+ export * from "./integrate.js";
30
31
  export * from "./kernels.js";
31
32
  export * from "./log.js";
32
33
  export * from "./log2.js";
@@ -54,10 +55,13 @@ export * from "./set.js";
54
55
  export * from "./setn.js";
55
56
  export * from "./sigmoid.js";
56
57
  export * from "./sin.js";
58
+ export * from "./smoothstep.js";
59
+ export * from "./smoothstepn.js";
57
60
  export * from "./softmax.js";
58
61
  export * from "./softplus.js";
59
62
  export * from "./sqrt.js";
60
63
  export * from "./step.js";
64
+ export * from "./stepn.js";
61
65
  export * from "./storage.js";
62
66
  export * from "./sub.js";
63
67
  export * from "./subn.js";
package/integrate.d.ts ADDED
@@ -0,0 +1,34 @@
1
+ import type { Fn } from "@thi.ng/api";
2
+ import type { ITensor } from "./api.js";
3
+ import { Tensor1 } from "./tensor.js";
4
+ /**
5
+ * Integrates given tensor along innermost dimension and writes result to 1D
6
+ * tensor `out` (or creates new one).
7
+ *
8
+ * @remarks
9
+ * The output tensor shape must match the innermost shape of the input: e.g. if
10
+ * input shape is `[2,3,4]`, then the output tensor must have a shape of `[4]`.
11
+ *
12
+ * @example
13
+ * ```ts tangle:../export/integrate.ts
14
+ * import { integrate, print, product, sum, tensor } from "@thi.ng/tensors";
15
+ *
16
+ * const input = tensor([[1, 2], [10, 20], [100, 200]]);
17
+ *
18
+ * // integrate using `sum()` (also default)
19
+ * // i.e. [1 + 10 + 100, 2 + 20 + 200]
20
+ * print(integrate(null, input, sum));
21
+ * // 111.0000 222.0000
22
+ *
23
+ * // integrate using `product()`
24
+ * // i.e. [1 * 10 * 100, 2 * 20 * 200]
25
+ * print(integrate(null, input, product));
26
+ * // 1000.0000 8000.0000
27
+ * ```
28
+ *
29
+ * @param out
30
+ * @param a
31
+ * @param fn
32
+ */
33
+ export declare const integrate: (out: Tensor1 | null, a: ITensor, fn?: Fn<ITensor, number>) => Tensor1;
34
+ //# sourceMappingURL=integrate.d.ts.map
package/integrate.js ADDED
@@ -0,0 +1,31 @@
1
+ import { ensureShape } from "./errors.js";
2
+ import { Tensor1 } from "./tensor.js";
3
+ import { sum } from "./sum.js";
4
+ const integrate = (out, a, fn = sum) => {
5
+ const { shape, dim } = a;
6
+ const odim = shape[shape.length - 1];
7
+ if (!out) {
8
+ out = new Tensor1(
9
+ a.type,
10
+ a.storage,
11
+ a.storage.alloc(odim),
12
+ [odim],
13
+ [1]
14
+ );
15
+ }
16
+ ensureShape(out, [odim]);
17
+ const {
18
+ data: odata,
19
+ stride: [tx],
20
+ offset: ox
21
+ } = out;
22
+ const select = new Array(dim).fill(-1);
23
+ for (let i = 0; i < odim; i++) {
24
+ select[dim - 1] = i;
25
+ odata[ox + i * tx] = fn(a.pick(select));
26
+ }
27
+ return out;
28
+ };
29
+ export {
30
+ integrate
31
+ };
package/normalize.d.ts CHANGED
@@ -7,5 +7,5 @@ import type { ITensor } from "./api.js";
7
7
  * @param a
8
8
  * @param n
9
9
  */
10
- export declare const normalize: (out: ITensor | null, a: ITensor, n?: number) => import("./tensor.js").Tensor1<any> | ITensor<number>;
10
+ export declare const normalize: (out: ITensor | null, a: ITensor, n?: number) => ITensor<number> | import("./tensor.js").Tensor1<any>;
11
11
  //# sourceMappingURL=normalize.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thi.ng/tensors",
3
- "version": "0.6.4",
3
+ "version": "0.8.0",
4
4
  "description": "1D/2D/3D/4D tensors with extensible polymorphic operations and customizable storage",
5
5
  "type": "module",
6
6
  "module": "./index.js",
@@ -39,19 +39,19 @@
39
39
  "tool:tangle": "../../node_modules/.bin/tangle src/**/*.ts"
40
40
  },
41
41
  "dependencies": {
42
- "@thi.ng/api": "^8.11.29",
43
- "@thi.ng/arrays": "^2.13.1",
44
- "@thi.ng/checks": "^3.7.9",
45
- "@thi.ng/equiv": "^2.1.85",
46
- "@thi.ng/errors": "^2.5.35",
47
- "@thi.ng/math": "^5.11.29",
48
- "@thi.ng/random": "^4.1.20",
49
- "@thi.ng/strings": "^3.9.15",
50
- "@thi.ng/vectors": "^8.3.1"
42
+ "@thi.ng/api": "^8.11.30",
43
+ "@thi.ng/arrays": "^2.13.2",
44
+ "@thi.ng/checks": "^3.7.10",
45
+ "@thi.ng/equiv": "^2.1.86",
46
+ "@thi.ng/errors": "^2.5.36",
47
+ "@thi.ng/math": "^5.11.30",
48
+ "@thi.ng/random": "^4.1.21",
49
+ "@thi.ng/strings": "^3.9.16",
50
+ "@thi.ng/vectors": "^8.3.2"
51
51
  },
52
52
  "devDependencies": {
53
- "esbuild": "^0.25.5",
54
- "typedoc": "^0.28.5",
53
+ "esbuild": "^0.25.6",
54
+ "typedoc": "^0.28.7",
55
55
  "typescript": "^5.8.3"
56
56
  },
57
57
  "keywords": [
@@ -64,6 +64,7 @@
64
64
  "array",
65
65
  "blur",
66
66
  "broadcast",
67
+ "conversion",
67
68
  "convolution",
68
69
  "data-oriented",
69
70
  "datastructure",
@@ -85,6 +86,7 @@
85
86
  "pool",
86
87
  "presets",
87
88
  "random",
89
+ "smoothstep",
88
90
  "step",
89
91
  "svd",
90
92
  "tensor",
@@ -197,6 +199,9 @@
197
199
  "./identity": {
198
200
  "default": "./identity.js"
199
201
  },
202
+ "./integrate": {
203
+ "default": "./integrate.js"
204
+ },
200
205
  "./kernels": {
201
206
  "default": "./kernels.js"
202
207
  },
@@ -278,6 +283,12 @@
278
283
  "./sin": {
279
284
  "default": "./sin.js"
280
285
  },
286
+ "./smoothstep": {
287
+ "default": "./smoothstep.js"
288
+ },
289
+ "./smoothstepn": {
290
+ "default": "./smoothstepn.js"
291
+ },
281
292
  "./softmax": {
282
293
  "default": "./softmax.js"
283
294
  },
@@ -290,6 +301,9 @@
290
301
  "./step": {
291
302
  "default": "./step.js"
292
303
  },
304
+ "./stepn": {
305
+ "default": "./stepn.js"
306
+ },
293
307
  "./storage": {
294
308
  "default": "./storage.js"
295
309
  },
@@ -325,5 +339,5 @@
325
339
  "status": "alpha",
326
340
  "year": 2018
327
341
  },
328
- "gitHead": "45e91ee75236e39fc87ea10fbabac1272bef62e3\n"
342
+ "gitHead": "56d8f088389b22192a06e9a395b5eecebf47697a\n"
329
343
  }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Componentwise computes smoothstep function for given nD tensor and thresholds
3
+ * `b` (low edge) and `c` (high edge). Writes result to `out`. If `out` is null,
4
+ * mutates `a`. Multi-method. Also see {@link step}.
5
+ *
6
+ * @remarks
7
+ * Same as GLSL `smoothstep()` (but with changed order of arguments).
8
+ *
9
+ * Reference:
10
+ *
11
+ * - https://registry.khronos.org/OpenGL-Refpages/gl4/html/smoothstep.xhtml
12
+ *
13
+ * @param out - output tensor
14
+ * @param a - input tensor
15
+ * @param b - input tensor (low edge)
16
+ * @param b - input tensor (high edge)
17
+ */
18
+ export declare const smoothStep: import("./api.js").TensorOpTTT<number>;
19
+ //# sourceMappingURL=smoothstep.d.ts.map
package/smoothstep.js ADDED
@@ -0,0 +1,6 @@
1
+ import { smoothStep as $ } from "@thi.ng/math/step";
2
+ import { defOpTTT } from "./defopttt.js";
3
+ const smoothStep = defOpTTT((a, b, c) => $(b, c, a));
4
+ export {
5
+ smoothStep
6
+ };
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Componentwise computes smoothstep function for given nD tensor and uniform
3
+ * scalar thresholds `b` (low edge) and `c` (high edge). Writes result to `out`.
4
+ * If `out` is null, mutates `a`. Multi-method. Also see {@link stepN}.
5
+ *
6
+ * @remarks
7
+ * Same as GLSL `smoothstep()` (but with changed order of arguments).
8
+ *
9
+ * Reference:
10
+ *
11
+ * - https://registry.khronos.org/OpenGL-Refpages/gl4/html/smoothstep.xhtml
12
+ *
13
+ * @param out - output tensor
14
+ * @param a - input tensor
15
+ * @param b - scalar (low edge)
16
+ * @param c - scalar (high edge)
17
+ */
18
+ export declare const smoothStepN: import("./api.js").MultiTensorOpImpl<import("./api.js").TensorOpTNN<number>>;
19
+ //# sourceMappingURL=smoothstepn.d.ts.map
package/smoothstepn.js ADDED
@@ -0,0 +1,6 @@
1
+ import { smoothStep as $ } from "@thi.ng/math/step";
2
+ import { defOpTNN } from "./defoptnn.js";
3
+ const smoothStepN = defOpTNN((a, b, c) => $(b, c, a));
4
+ export {
5
+ smoothStepN
6
+ };
package/step.d.ts CHANGED
@@ -1,16 +1,18 @@
1
1
  /**
2
- * Componentwise computes step function for given nD tensor and uniform scalar
3
- * threshold `n`. Writes result to `out`. If `out` is null, mutates `a`.
4
- * Multi-method.
2
+ * Componentwise computes step function for given nD tensor and threshold `b`.
3
+ * Writes result to `out`. If `out` is null, mutates `a`. Multi-method. Also see
4
+ * {@link stepN} and {@link smoothStep}.
5
5
  *
6
6
  * @remarks
7
- * Same logic as GLSL `step()` (but with different order of arguments). If
8
- * `n=0`, the op becomes the Heaviside function:
9
- * https://en.wikipedia.org/wiki/Heaviside_step_function
7
+ * Same logic as GLSL `step()` (but with swapped order of arguments).
8
+ *
9
+ * Reference:
10
+ *
11
+ * - https://registry.khronos.org/OpenGL-Refpages/gl4/html/step.xhtml
10
12
  *
11
13
  * @param out - output tensor
12
14
  * @param a - input tensor
13
- * @param n - scalar
15
+ * @param b - input tensor (threshold)
14
16
  */
15
- export declare const stepN: import("./api.js").MultiTensorOpImpl<import("./api.js").TensorOpTN<number>>;
17
+ export declare const step: import("./api.js").TensorOpTT<number>;
16
18
  //# sourceMappingURL=step.d.ts.map
package/step.js CHANGED
@@ -1,5 +1,5 @@
1
- import { defOpTN } from "./defoptn.js";
2
- const stepN = defOpTN((a, b) => a >= b ? 1 : 0);
1
+ import { defOpTT } from "./defoptt.js";
2
+ const step = defOpTT((a, b) => a >= b ? 1 : 0);
3
3
  export {
4
- stepN
4
+ step
5
5
  };
package/stepn.d.ts ADDED
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Componentwise computes step function for given nD tensor and uniform scalar
3
+ * threshold `n`. Writes result to `out`. If `out` is null, mutates `a`.
4
+ * Multi-method. Also see {@link step} and {@link smoothStep}.
5
+ *
6
+ * @remarks
7
+ * Same logic as GLSL `step()` (but with different order of arguments). If
8
+ * `n=0`, the op becomes the Heaviside function:
9
+ * https://en.wikipedia.org/wiki/Heaviside_step_function
10
+ *
11
+ * @param out - output tensor
12
+ * @param a - input tensor
13
+ * @param n - scalar
14
+ */
15
+ export declare const stepN: import("./api.js").MultiTensorOpImpl<import("./api.js").TensorOpTN<number>>;
16
+ //# sourceMappingURL=stepn.d.ts.map
package/stepn.js ADDED
@@ -0,0 +1,5 @@
1
+ import { defOpTN } from "./defoptn.js";
2
+ const stepN = defOpTN((a, b) => a >= b ? 1 : 0);
3
+ export {
4
+ stepN
5
+ };
package/tensor.d.ts CHANGED
@@ -29,6 +29,7 @@ export declare abstract class ATensor<T = number> implements ITensor<T> {
29
29
  abstract set(pos: NumericArray, v: T): this;
30
30
  hi(pos: NumericArray): this;
31
31
  lo(pos: NumericArray): this;
32
+ crop(pos: NumericArray, size: NumericArray): this;
32
33
  step(select: NumericArray): typeof this;
33
34
  pick(select: NumericArray): ITensor<T>;
34
35
  pack(storage?: ITensorStorage<T>): typeof this;
package/tensor.js CHANGED
@@ -101,6 +101,17 @@ class ATensor {
101
101
  offset
102
102
  );
103
103
  }
104
+ crop(pos, size) {
105
+ const { shape, offset } = __crop(pos, size, this);
106
+ return new this.constructor(
107
+ this.type,
108
+ this.storage,
109
+ this.data,
110
+ shape,
111
+ this.stride,
112
+ offset
113
+ );
114
+ }
104
115
  step(select) {
105
116
  const { shape, stride, offset } = __step(select, this);
106
117
  return new this.constructor(
@@ -500,6 +511,7 @@ const __lo = (select, { shape, stride, offset }) => {
500
511
  const newShape = [];
501
512
  for (let i = 0, n = shape.length; i < n; i++) {
502
513
  const x = select[i];
514
+ if (x > shape[i]) illegalShape(select);
503
515
  newShape.push(
504
516
  x >= 0 ? (offset += stride[i] * x, shape[i] - x) : shape[i]
505
517
  );
@@ -510,10 +522,16 @@ const __hi = (select, { shape }) => {
510
522
  const newShape = [];
511
523
  for (let i = 0, n = shape.length; i < n; i++) {
512
524
  const x = select[i];
525
+ if (x > shape[i]) illegalShape(select);
513
526
  newShape.push(x > 0 ? x : shape[i]);
514
527
  }
515
528
  return newShape;
516
529
  };
530
+ const __crop = (lo, hi, src) => {
531
+ const res = __lo(lo, src);
532
+ const shape = __hi(hi, res);
533
+ return { ...res, shape };
534
+ };
517
535
  const __step = (select, { shape, stride, offset }) => {
518
536
  const newShape = shape.slice();
519
537
  const newStride = stride.slice();