Skip to content

Commit

Permalink
In-place division/multiplication by scalar, closes #20
Browse files Browse the repository at this point in the history
  • Loading branch information
edubart committed Sep 15, 2017
1 parent f35e677 commit 1282503
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 6 deletions.
8 changes: 4 additions & 4 deletions src/arraymancer/data_structure.nim
Expand Up @@ -29,10 +29,10 @@ type
## - ``strides``: Numbers of items to skip to get the next item along a dimension.
## - ``offset``: Offset to get the first item of the Tensor. Note: offset can be negative, in particular for slices.
## - ``data``: A sequence that holds the actual data
shape: seq[int]
strides: seq[int]
offset: int
data: seq[T] # Perf note: seq are always deep copied on "var" assignement.
shape*: seq[int]
strides*: seq[int]
offset*: int
data*: seq[T] # Perf note: seq are always deep copied on "var" assignement.

CudaTensor*[T: SomeReal] = object
## Tensor data structure, stored on Nvidia GPU (Cuda)
Expand Down
10 changes: 9 additions & 1 deletion src/arraymancer/operators_blas_l1.nim
Expand Up @@ -92,7 +92,15 @@ proc `*`*[T: SomeNumber](t: Tensor[T], a: T): Tensor[T] {.noSideEffect, inline.}
## Element-wise multiplication by a scalar
a * t

proc `*=`*[T: SomeNumber](t: var Tensor[T], a: T) {.noSideEffect.} =
## Element-wise multiplication by a scalar (in-place)
t.apply(proc(x: T): T = a * x)

proc `/`*[T: SomeNumber](t: Tensor[T], a: T): Tensor[T] {.noSideEffect.} =
## Element-wise division by a scalar
proc f(x: T): T = x / a
return t.fmap(f)
return t.fmap(f)

proc `/=`*[T: SomeNumber](t: var Tensor[T], a: T): Tensor[T] {.noSideEffect.} =
## Element-wise division by a scalar (in-place)
t.apply(proc(x: T): T = a / x)
7 changes: 7 additions & 0 deletions src/arraymancer/ufunc.nim
Expand Up @@ -35,6 +35,13 @@ proc fmap*[T, U](t: Tensor[T], g: T -> U): Tensor[U] {.noSideEffect.}=
result.data[i] = g(val)
inc i

proc apply*[T](t: var Tensor[T], g: T -> T) {.noSideEffect.}=
## Map a elements inplace with unary function T -> T
var i = 0 # TODO: use pairs/enumerate instead - pending https://forum.nim-lang.org/t/2972
for val in t:
t.data[i] = g(val)
inc i

proc fmap2*[T, U, V](t1: Tensor[T], t2: Tensor[U], g: (T,U) -> V): Tensor[V] {.noSideEffect.}=
## Map a binary function (T,U) -> V on Tensor[T]
## It applies the function to each matching elements
Expand Down
12 changes: 11 additions & 1 deletion tests/test_operators_blas.nim
Expand Up @@ -163,6 +163,17 @@ suite "BLAS (Basic Linear Algebra Subprograms)":
let ufl_expected = @[2'f64, 6, -10].toTensor()
check: ufl_expected / 2 == u_float

test "Multiplication/division by scalar (inplace)":
var u_int = @[1, 3, -5].toTensor()
let u_expected = @[2, 6, -10].toTensor()
u_int *= 2
check: u_int == u_expected

var u_float = @[1'f64, 3, -5].toTensor()
let ufl_expected = @[2'f64, 6, -10].toTensor()
u_float *= 2.0'f64
check: ufl_expected == u_float

test "Tensor addition and substraction":
let u_int = @[1, 3, -5].toTensor()
let v_int = @[1, 1, 1].toTensor()
Expand All @@ -172,7 +183,6 @@ suite "BLAS (Basic Linear Algebra Subprograms)":
check: u_int + v_int == expected_add
check: u_int - v_int == expected_sub


test "Tensor negative":
let u_int = @[-1, 0, 2].toTensor()
let expected_add = @[1, 0, -2].toTensor()
Expand Down

0 comments on commit 1282503

Please sign in to comment.