Skip to content

Commit 9cf5b41

Browse files
Fix issue 639 (#640)
* Make newTensorUninit[T]() create a rank-1 empty tensor Similar to same change done to `newTensor` on the previous commit. * Make newTensor[T]() create a rank-1 empty tensor Up until now calling newTensor without arguments would create a rank-0 tensor which does not work well (e.g. it reports its size as size 0)! Instead we now create a rank-1 empty tensor when no shape is provided. It is still possible to explicitly create a rank-0 tensor by explicitly passing an empty shape (i.e. `[]`) to newTensor (e.g. `newTensor[float]([])`). This can be useful to create "sentinel" values for procedures that take tensors as arguments. * Fix issue #639 (`size` returns 1 for rank-0 tensors) This fixes #639. While this adds an extra check to `size` which might be called frequently, I have not seen a major difference on several of the benchmarks.
1 parent 7ad9903 commit 9cf5b41

File tree

3 files changed

+22
-11
lines changed

3 files changed

+22
-11
lines changed

src/arraymancer/laser/dynamic_stack_arrays.nim

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ func `$`*(a: DynamicStackArray): string =
9191
result.add("]")
9292

9393
func product*[T:SomeNumber](a: DynamicStackArray[T]): T =
94+
if unlikely(a.len == 0):
95+
return 0
9496
result = 1
9597
for value in items(a):
9698
result *= value

src/arraymancer/laser/tensor/initialization.nim

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,14 @@ proc setZero*[T](t: var Tensor[T], check_contiguous: static bool = true) =
184184
chunk_size * sizeof(T)
185185
)
186186

187-
proc newTensor*[T](shape: varargs[int]): Tensor[T] =
187+
proc newTensor*[T](shape: varargs[int] = [0]): Tensor[T] =
188+
## Create a new tensor of type T with the given shape.
189+
##
190+
## If no shape is provided, we create an empty rank-1 tensor.
191+
## To create a rank-0 tensor, explicitly pass and empty shape `[]`.
192+
##
193+
## Note that in general it is not a good idea to use rank-0 tensors.
194+
## However, they can be used as "sentinel" values for Tensor arguments.
188195
var size: int
189196
initTensorMetadata(result, size, shape)
190197
allocCpuStorage(result.storage, size)
@@ -193,6 +200,7 @@ proc newTensor*[T](shape: varargs[int]): Tensor[T] =
193200
setZero(result, check_contiguous = false)
194201

195202
proc newTensor*[T](shape: Metadata): Tensor[T] =
203+
## Create a new tensor of type T with the given shape.
196204
var size: int
197205
initTensorMetadata(result, size, shape)
198206
allocCpuStorage(result.storage, size)

src/arraymancer/tensor/init_cpu.nim

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,17 @@ import std / [random, math]
2323

2424
export initialization
2525

26-
proc newTensorUninit*[T](shape: varargs[int]): Tensor[T] {.noinit, inline.} =
27-
## Creates a new Tensor on Cpu backend
26+
proc newTensorUninit*[T](shape: varargs[int] = [0]): Tensor[T] {.noinit, inline.} =
27+
## Creates a new uninitialized Tensor of type `T` on the Cpu backend
2828
## Input:
29-
## - Shape of the Tensor
30-
## - Type of its elements
29+
## - Shape of the Tensor (defaults to an empty rank-1 tensor)
3130
## Result:
3231
## - A Tensor of the proper shape with NO initialization
33-
## Warning ⚠
34-
## Tensor data is uninitialized and contains garbage.
32+
## Warnings ⚠:
33+
## - Tensor data is uninitialized and contains garbage.
34+
## - If no shape is provided, a 1D tensor of size 0 is created.
35+
## It is possible to create a rank-0 tensor by explicitly
36+
## providing an empty shape `[]` (e.g. `newTensorUninit[float]([])`).
3537
var size: int
3638
initTensorMetadata(result, size, shape)
3739
allocCpuStorage(result.storage, size)
@@ -42,14 +44,13 @@ proc newTensorUninit*[T](size: int): Tensor[T] {.noinit, inline.} =
4244
result = newTensorUninit[T]([size])
4345

4446
proc newTensorUninit*[T](shape: Metadata): Tensor[T] {.noinit, inline.} =
45-
## Creates a new Tensor on Cpu backend
47+
## Creates a new uninitialized Tensor of type `T` on the Cpu backend
4648
## Input:
4749
## - Shape of the Tensor
48-
## - Type of its elements
4950
## Result:
5051
## - A Tensor of the proper shape with NO initialization
51-
## Warning ⚠
52-
## Tensor data is uninitialized and contains garbage.
52+
## Warning ⚠:
53+
## - Tensor data is uninitialized and contains garbage.
5354
var size: int
5455
initTensorMetadata(result, size, shape)
5556
allocCpuStorage(result.storage, size)

0 commit comments

Comments
 (0)