-
-
Notifications
You must be signed in to change notification settings - Fork 96
/
data_structure.nim
114 lines (101 loc) · 3.62 KB
/
data_structure.nim
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# Copyright 2017 Mamy André-Ratsimbazafy
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
type
Backend* = enum
## ``Backend`` for tensor computation and memory allocation.
##
## Only Cpu is supported for now.
Cpu
# Cuda
# OpenCL
# Magma
Tensor*[B: static[Backend]; T] = object
# Size of the datastructure is 32 bytes - perfect !
## Tensor data structure
## - ``shape``: Dimensions of the tensor
## - ``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.
template shape*(t: Tensor): seq[int] =
## Input:
## - A tensor
## Returns:
## - Its shape
t.shape
template strides*(t: Tensor): seq[int] =
## Input:
## - A tensor
## Returns:
## - Its strides
t.strides
template offset*(t: Tensor): int =
## Input:
## - A tensor
## Returns:
## - Its offset
t.offset
template rank*(t: Tensor): int =
## Input:
## - A tensor
## Returns:
## - Its shape
##
## - 0 for scalar (unfortunately cannot be stored)
## - 1 for vector
## - 2 for matrices
## - N for N-dimension array
##
t.shape.len
proc shape_to_strides(shape: seq[int]): seq[int] {.noSideEffect.} =
## Compute strides matching with dimensions.
return (shape & 1)[1..shape.len].scanr(a * b)
proc is_C_contiguous(t: Tensor): bool {.noSideEffect.}=
## Check if C convention / Row Major
result = t.strides == t.shape.shape_to_strides
result = result and t.strides[t.strides.high] == 1
proc is_F_contiguous(t: Tensor): bool {.noSideEffect.}=
## Check if Fortran convention / Column Major
result = t.strides.reversed == t.shape.reversed.shape_to_strides
result = result and t.strides[0] == 1
proc isContiguous(t: Tensor): bool {.noSideEffect.}=
return t.is_C_contiguous or t.is_F_contiguous
proc getTransposeTarget(t: Tensor): TransposeType {.noSideEffect.}=
## Default layout is Row major.
## Everytime it is worth it or fused with a BLAS operation we change the strides to Row-Major
if is_C_contiguous(t): return TransposeType.noTranspose
elif is_F_contiguous(t): return TransposeType.transpose
else: raise newException(ValueError,"Operation not supported for this matrix. It has a non-contiguous layout")
template get_data_ptr*[B,T](t: Tensor[B,T]): ptr T =
## Input:
## - A tensor
## Returns:
## - A pointer to the start of its data
unsafeAddr(t.data[0])
proc shallowCopy*[B,T](t: var Tensor[B,T]): Tensor[B,T] {.noSideEffect.}=
## Input:
## - A ``var`` tensor
## Returns:
## - A shallow copy.
##
## WARNING !
## Both tensors shares the same memory. Data modification on one will be reflected on the other.
## However modifying the shape, strides or offset will not affect the other.
result.shape = t.shape
result.strides = t.strides
result.offset = t.offset
shallowCopy(result.data, t.data)