Skip to content

Commit b734c00

Browse files
0.4.0 (#35)
* Move creation methods to Tensor * moved more creation methods * 0.3.2 * Fix failing tests * first pass at new tensor * check in work * placeholder * linear algebra start * opencl * copy code from other branch * sucky frame * dataframe from other branch * lint * added accumulation * cleaning up build * README tweaks * beginning ci work * Work on specific c libs * Final changes before release
1 parent 73d0c88 commit b734c00

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+13138
-4210
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,5 @@ elementwise_arraymancer
1818
elementwise_num
1919
matmul_arraymancer
2020
matmul_num
21+
22+
*.o

.gitmodules

-3
This file was deleted.

.travis.yml

-12
This file was deleted.

LICENSE

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
The MIT License (MIT)
22

3-
Copyright (c) 2019 Chris Zimmerman
3+
Copyright (c) 2020 Crystal Data Contributors
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

Makefile

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CC = clang
2+
CFLAGS = -Ofast -march=native -Wall -std=c99
3+
4+
ext: kmeans random
5+
6+
kmeans: src/c/kmeans/asa136.c
7+
$(CC) -c src/c/kmeans/asa136.c -o src/c/kmeans/asa136.o -I. $(CFLAGS)
8+
9+
random: src/c/random/ranlib.c
10+
$(CC) -c src/c/random/ranlib.c -o src/c/random/ranlib.o -I. $(CFLAGS)

README.md

+176-55
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
![num.cr](https://raw.githubusercontent.com/crystal-data/bottle/rename/static/numcr_logo.png)
22

33
[![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)
55

66
Num.cr is the core shard needed for scientific computing with Crystal
77

@@ -13,35 +13,23 @@ Num.cr is the core shard needed for scientific computing with Crystal
1313
It provides:
1414

1515
- 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`
1919

2020
## Prerequisites
2121

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.
4533

4634
## Installation
4735

@@ -53,74 +41,207 @@ dependencies:
5341
github: crystal-data/num.cr
5442
```
5543

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
5763

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.
6166

6267
```crystal
6368
[1, 2, 3].to_tensor
6469
Tensor.from_array [1, 2, 3]
6570
Tensor(UInt8).zeros([3, 3, 2])
6671
Tensor.random(0.0...1.0, [2, 2, 2])
6772
68-
ClTensor(Float32).zeros_like(some_tensor)
73+
ClTensor(Float32).zeros([3, 2, 2])
6974
ClTensor(Float64).full([3, 4, 5], 3.8)
7075
```
7176

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.
7482

7583
```crystal
7684
a = [1, 2, 3, 4].to_tensor
7785
b = [[3, 4, 5, 6], [5, 6, 7, 8]].to_tensor
7886
7987
# Convert a Tensor to a GPU backed Tensor
80-
acl = a.astype(Float64).opencl
88+
acl = a.astype(Float64).gpu
8189
8290
puts Num.add(a, b)
8391
8492
# a is broadcast to b's shape
8593
# [[ 4, 6, 8, 10],
8694
# [ 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+
```
87113

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 }
89122
90-
# [[1, 2],
91-
# [3, 4]]
123+
puts a.transpose
92124
93-
puts b.transpose
125+
# [[[ 0, 4, 8],
126+
# [ 2, 6, 10]],
127+
#
128+
# [[ 1, 5, 9],
129+
# [ 3, 7, 11]]]
94130
95-
# [[3, 5],
96-
# [4, 6],
97-
# [5, 7],
98-
# [6, 8]]
131+
puts a.reshape(6, 2)
99132
100-
puts Num.cos(acl).cpu
133+
# [[ 0, 1],
134+
# [ 2, 3],
135+
# [ 4, 5],
136+
# [ 6, 7],
137+
# [ 8, 9],
138+
# [10, 11]]
101139
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
103157
```
104158

105-
Both CPU backed Tensors and GPU backed Tensors support linear algebra routines
106-
backed by optimized BLAS libraries.
159+
### Linear Algebra
107160

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.
111163

112-
acl = a.opencl
113-
bcl = b.opencl
164+
```crystal
165+
a = [[1, 2], [3, 4]].to_tensor.map &.to_f32
114166
115167
puts a.inv
116168
117169
# [[-2 , 1 ],
118170
# [1.5 , -0.5]]
119171
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])
121225
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
124245
```
125246

126247
Review the documentation for full implementation details, and if something is missing,

shard.yml

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: num
2-
version: 0.3.2
2+
version: 0.4.0
33

44
authors:
55
- Chris Zimmerman <[email protected]>
@@ -11,3 +11,6 @@ license: MIT
1111
dependencies:
1212
opencl:
1313
github: crystal-data/opencl.cr
14+
15+
scripts:
16+
postinstall: make ext

0 commit comments

Comments
 (0)