1
1
![ num.cr] ( https://raw.githubusercontent.com/crystal-data/bottle/rename/static/numcr_logo.png )
2
2
3
3
[ ![ Join the chat at https://gitter.im/crystal-data/bottle ] ( https://badges.gitter.im/crystal-data/bottle.svg )] ( https://gitter.im/crystal-data/bottle?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge )
4
- [ ![ Build Status ] ( https://travis-ci .com/crystal-data/num.cr.svg?branch=master )] ( https://travis-ci.com/crystal-data/num.cr )
4
+ ![ Crystal CI ] ( https://github .com/crystal-data/num.cr/workflows/Crystal%20CI/badge.svg )
5
5
6
6
Num.cr is the core shard needed for scientific computing with Crystal
7
7
@@ -13,35 +13,23 @@ Num.cr is the core shard needed for scientific computing with Crystal
13
13
It provides:
14
14
15
15
- An n-dimensional ` Tensor ` data structure
16
- - sophisticated reduction and accumulation routines
17
- - data structures that can easily be passed to C libraries
18
- - powerful linear algebra routines backed by LAPACK and BLAS
16
+ - Efficient ` map ` , ` reduce ` and ` accumulate ` routines
17
+ - GPU accelerated routines backed by ` OpenCL `
18
+ - Linear algebra routines backed by ` LAPACK ` and ` BLAS `
19
19
20
20
## Prerequisites
21
21
22
- Num.cr relies on various BLAS and LAPACK implementations to provide performant linear
23
- algebra routines. The defaults are OpenBLAS and Lapacke. On Darwin, the Accelerate
24
- framework is used by default. Num.cr also allows for computing run on a GPU, backed
25
- by OpenCL, with BLAS operations backed by ClBlast. Please review the relevant installation
26
- instructions for these libraries if you would like to take advantage of their features.
27
-
28
- ## Usage
29
-
30
- Num.cr provides data structures that facilitate element-wise operations,
31
- accumulations, and reductions. While some operations are backed by BLAS
32
- and LaPACK, many vectorized operations use iteration written in Crystal.
33
- The primary goal of this library was to provide a NumPy like interface in
34
- Crystal, and performance will be revisited constantly as the library is
35
- improved.
36
-
37
- Contributing
38
- ------------
39
- Num.cr requires help in many different ways to continue to grow as a shard.
40
- Contributions such as high level documentation and code quality checks are needed just
41
- as much as API enhancements. If you are considering larger scale contributions
42
- that extend beyond minor enhancements and bug fixes, contact Crystal Data
43
- in order to be added to the organization to gain access to review and merge
44
- permissions.
22
+ ` Num.cr ` aims to be a scientific computing library written in pure Crystal.
23
+ All standard operations and data structures are written in Crystal. Certain
24
+ routines, primarily linear algebra routines, are instead provided by a
25
+ ` BLAS ` or ` LAPACK ` implementation.
26
+
27
+ Several implementations can be used, including ` Cblas ` , ` Openblas ` , and the
28
+ ` Accelerate ` framework on Darwin systems. For GPU accelerated ` BLAS ` routines,
29
+ the ` ClBlast ` library is required.
30
+
31
+ ` Num.cr ` also supports ` Tensor ` s stored on a ` GPU ` . This is currently limited
32
+ to ` OpenCL ` , and a valid ` OpenCL ` installation and device(s) are required.
45
33
46
34
## Installation
47
35
@@ -53,74 +41,207 @@ dependencies:
53
41
github: crystal-data/num.cr
54
42
```
55
43
56
- ## Getting started with Num.cr
44
+ Several third-party libraries are required to use certain features of ` Num.cr ` .
45
+ They are:
46
+
47
+ - BLAS
48
+ - LAPACK
49
+ - OpenCL
50
+ - ClBlast
51
+
52
+ While not at all required, they provide additional functionality than is
53
+ provided by the basic library.
54
+
55
+ ## Just show me the code
56
+
57
+ The core data structure implemented by ` Num.cr ` is the ` Tensor ` , an N-dimensional
58
+ data structure. A ` Tensor ` supports slicing, mutation, permutation, reduction,
59
+ and accumulation. A ` Tensor ` can be a view of another ` Tensor ` , and can support
60
+ either C-style or Fortran-style storage.
61
+
62
+ ### Creation
57
63
58
- The core data structure of Num.cr is the ` Tensor ` , a flexible N-dimensional data structure.
59
- There are many ways to initialize a ` Tensor ` , or a ` ClTensor ` if you need GPU accelerated
60
- operations.
64
+ There are many ways to initialize a ` Tensor ` . Most creation methods can
65
+ allocate a ` Tensor ` backed by either ` CPU ` or ` GPU ` based storage.
61
66
62
67
``` crystal
63
68
[1, 2, 3].to_tensor
64
69
Tensor.from_array [1, 2, 3]
65
70
Tensor(UInt8).zeros([3, 3, 2])
66
71
Tensor.random(0.0...1.0, [2, 2, 2])
67
72
68
- ClTensor(Float32).zeros_like(some_tensor )
73
+ ClTensor(Float32).zeros([3, 2, 2] )
69
74
ClTensor(Float64).full([3, 4, 5], 3.8)
70
75
```
71
76
72
- Tensors support numerous mathematical operations and manipulation routines, including
73
- operations requiring broadcasting to other shapes.
77
+ ### Operations
78
+
79
+ A ` Tensor ` supports a wide variety of numerical operations. Many of these
80
+ operations are provided by ` Num.cr ` , but any operation can be mapped across
81
+ one or more ` Tensor ` s using sophisticated broadcasted mapping routines.
74
82
75
83
``` crystal
76
84
a = [1, 2, 3, 4].to_tensor
77
85
b = [[3, 4, 5, 6], [5, 6, 7, 8]].to_tensor
78
86
79
87
# Convert a Tensor to a GPU backed Tensor
80
- acl = a.astype(Float64).opencl
88
+ acl = a.astype(Float64).gpu
81
89
82
90
puts Num.add(a, b)
83
91
84
92
# a is broadcast to b's shape
85
93
# [[ 4, 6, 8, 10],
86
94
# [ 6, 8, 10, 12]]
95
+ ```
96
+
97
+ When operating on more than two ` Tensor ` s, it is recommended to use ` map `
98
+ rather than builtin functions to avoid the allocation of intermediate
99
+ results. All ` map ` operations support broadcasting.
100
+
101
+ ``` crystal
102
+ a = [1, 2, 3, 4].to_tensor
103
+ b = [[3, 4, 5, 6], [5, 6, 7, 8]].to_tensor
104
+ c = [3, 5, 7, 9].to_tensor
105
+
106
+ a.map(b, c) do |i, j, k|
107
+ i + 2 / j + k * 3.5
108
+ end
109
+
110
+ # [[12.1667, 20 , 27.9 , 35.8333],
111
+ # [11.9 , 19.8333, 27.7857, 35.75 ]]
112
+ ```
87
113
88
- puts a.reshape(2, 2)
114
+ ### Mutation
115
+
116
+ ` Tensor ` s support flexible slicing and mutation operations. Many of these
117
+ operations return views, not copies, so any changes made to the results might
118
+ also be reflected in the parent.
119
+
120
+ ``` crystal
121
+ a = Tensor.new([3, 2, 2]) { |i| i }
89
122
90
- # [[1, 2],
91
- # [3, 4]]
123
+ puts a.transpose
92
124
93
- puts b.transpose
125
+ # [[[ 0, 4, 8],
126
+ # [ 2, 6, 10]],
127
+ #
128
+ # [[ 1, 5, 9],
129
+ # [ 3, 7, 11]]]
94
130
95
- # [[3, 5],
96
- # [4, 6],
97
- # [5, 7],
98
- # [6, 8]]
131
+ puts a.reshape(6, 2)
99
132
100
- puts Num.cos(acl).cpu
133
+ # [[ 0, 1],
134
+ # [ 2, 3],
135
+ # [ 4, 5],
136
+ # [ 6, 7],
137
+ # [ 8, 9],
138
+ # [10, 11]]
101
139
102
- # [0.540302 , -0.416147, -0.989992, -0.653644]
140
+ puts a[..., 1]
141
+
142
+ # [[ 2, 3],
143
+ # [ 6, 7],
144
+ # [10, 11]]
145
+
146
+ puts a[1..., {..., -1}]
147
+
148
+ # [[[ 6, 7],
149
+ # [ 4, 5]],
150
+ #
151
+ # [[10, 11],
152
+ # [ 8, 9]]]
153
+
154
+ puts a[0, 1, 1].value
155
+
156
+ # 3
103
157
```
104
158
105
- Both CPU backed Tensors and GPU backed Tensors support linear algebra routines
106
- backed by optimized BLAS libraries.
159
+ ### Linear Algebra
107
160
108
- ``` crystal
109
- a = [[1, 2], [3, 4]].to_tensor.astype(Float32)
110
- b = [[3, 4], [5, 6]].to_tensor.astype(Float32)
161
+ ` Tensor ` s provide easy access to power Linear Algebra routines backed by
162
+ LAPACK and BLAS implementations, and ClBlast for GPU backed ` Tensor ` s.
111
163
112
- acl = a.opencl
113
- bcl = b.opencl
164
+ ``` crystal
165
+ a = [[1, 2], [3, 4]].to_tensor.map &.to_f32
114
166
115
167
puts a.inv
116
168
117
169
# [[-2 , 1 ],
118
170
# [1.5 , -0.5]]
119
171
120
- puts acl.matmul(bcl).cpu
172
+ puts a.eigvals
173
+
174
+ # [-0.372281, 5.37228 ]
175
+
176
+ acl = a.opencl
177
+ bcl = a.opencl
178
+
179
+ puts acl.gemm(bcl).cpu
180
+
181
+ # [[7 , 10],
182
+ # [15, 22]]
183
+
184
+ puts a.matmul(a)
185
+
186
+ # [[7 , 10],
187
+ # [15, 22]]
188
+ ```
189
+
190
+ ### DataFrames
191
+
192
+ For more structured data, consider using a ` DataFrame `
193
+
194
+ ``` crystal
195
+ df = DataFrame.from_items(
196
+ foo: [1, 2, 3, 4, 5].to_tensor,
197
+ bar: [2.73, 3.1, 4.8, 5.1, 3.2],
198
+ )
199
+
200
+ puts df
201
+
202
+ # foo bar
203
+ # 0 1 2.73
204
+ # 1 2 3.1
205
+ # 2 3 4.8
206
+ # 3 4 5.1
207
+ # 4 5 3.2
208
+ ```
209
+
210
+ A ` DataFrame ` maintains types while still providing convenient
211
+ mapping and reduction operations
212
+
213
+ ``` crystal
214
+ puts df.c[:foo]
215
+
216
+ # 0 1
217
+ # 1 2
218
+ # 2 3
219
+ # 3 4
220
+ # 4 5
221
+ # Name: foo
222
+ # dtype: Int32
223
+
224
+ puts typeof(df.c[:foo])
121
225
122
- # [[13, 16],
123
- # [29, 36]]
226
+ # Series(Int32, Int32)
227
+
228
+ puts df.sum
229
+
230
+ # foo 15
231
+ # bar 18.93
232
+ ```
233
+
234
+ With operations that broadcast across the ` DataFrame `
235
+
236
+ ``` crystal
237
+ puts df.greater(df.mean)
238
+
239
+ # foo bar
240
+ # 0 false false
241
+ # 1 false false
242
+ # 2 false true
243
+ # 3 true true
244
+ # 4 true false
124
245
```
125
246
126
247
Review the documentation for full implementation details, and if something is missing,
0 commit comments