tensor

Tensor is a powerful, multi-typed N-dimensional array similar to numpy's ndarray without reflection overhead.
Table of Contents
- Getting Started
- Examples
- Milestones
- Contributing
- Similar projects
- Benchmarks
- Versioning
- License
- Acknowledgments
Getting Started
The goal of this project is to create a simple, fast and easy to use N-dimensional array structure with an idiomatic Go interface that supports multiple data types. Here is the current state of this project:
- single and idiomatic API.
- support for all Go's boolean, numeric and string types.
- no reflection under the hood.
- no external dependencies.
- pure Go implementation.
- interoperability with numpy's NPY format via binary
Tensorrepresentation. - completely open source and free to use.
Installation
Just like other Go libraries, you can get this package via go get:
$ go get github.com/ppknap/tensorThen, just import it in your application:
import "github.com/ppknap/tensor"Requirements
- Go1.10+
Examples
Softmax function
Following code shows how to implement a simple softmax function for vectors and matrices. Note, that the returned tensor's data type will be inherited from a given argument.
package main
import (
"fmt"
"github.com/ppknap/tensor"
)
func softmax(t *tensor.Tensor) *tensor.Tensor {
var sm = t.Copy()
if sm.NDim() == 1 {
return sm.Divide(sm.Exp().Sum())
}
for _, row := range sm.Split(0) {
row.Divide(row.Subtract(row.Max()).Exp().Sum())
}
return sm
}
func main() {
mat := tensor.NewMatrix([][]float64{
{1, 2, 3, 6},
{2, 4, 5, 6},
{1, 2, 3, 6},
})
fmt.Printf("Softmax of:%v\nis equal to:%.6f\n", mat, softmax(mat))
}Output:
Softmax of:
[[1 2 3 6]
[2 4 5 6]
[1 2 3 6]]
is equal to:
[[0.006269 0.017040 0.046320 0.930370]
[0.012038 0.088947 0.241783 0.657233]
[0.006269 0.017040 0.046320 0.930370]]
Dot product
This example shows how to compute a dot product of two matrices. Note that when working with tensors, one doesn't have to worry about the underlying data types for most of the time.
package main
import (
"fmt"
"github.com/ppknap/tensor"
)
func main() {
res := tensor.Dot(
tensor.NewMatrix([][]int{
{4, 5, 1},
{2, 0, 3},
{1, 1, 1},
}),
tensor.NewMatrix([][]float64{
{1.0, 0, 0.5},
{0.0, 1, 0.0},
{0.5, 1, 1.5},
}),
)
fmt.Printf("Dot result:%v (dtype: %s)\n", res, res.DType())
}Output:
Dot result:
[[4.5 6 3.5]
[3.5 3 5.5]
[1.5 2 2]] (dtype: float64)
Element access
One can walk and access all elements in the tensor. This example shows how to randomly distribute elements from a source tensor to a destination one.
package main
import (
"fmt"
"math/rand"
"github.com/ppknap/tensor"
)
func main() {
var words = tensor.NewVector([]string{"Tom", "Alice", "John", "Kate"})
f := func(t *tensor.Tensor, pos []int) bool {
t.ItemSet(words.ItemAt(rand.Intn(words.Len())), pos...)
return true
}
fmt.Printf("Result:%q\n", tensor.New(5, 5).Walk(f))
}Example output:
Result:
[["Alice" "Kate" "Kate" "Kate" "Alice"]
[ "John" "Alice" "Tom" "Tom" "Tom"]
[ "John" "Kate" "John" "Alice" "Tom"]
[ "John" "Kate" "Alice" "Alice" "John"]
[ "Kate" "John" "Tom" "John" "Kate"]]
Splitting
Splitting is a powerful feature that enables complex operations on selected parts of a tensor. This example shows how to fill every third column of a matrix with random values.
package main
import (
"fmt"
"github.com/ppknap/tensor"
)
func main() {
mat := tensor.New(3, 100)
for i, vec := range mat.Split(1) {
if i%3 == 0 {
vec.Rand().Fill()
}
}
fmt.Printf("Result:%4.2f (dtype: %s)\n", mat, mat.DType())
}Example output:
Result:
[[0.95 0.00 0.00 0.72 ... 0.49 0.00 0.00 0.26]
[0.24 0.00 0.00 0.65 ... 0.38 0.00 0.00 0.64]
[0.66 0.00 0.00 0.94 ... 0.53 0.00 0.00 0.67]] (dtype: float64)
Conversions
It is possible to easily convert a tensor object from/to Go basic types.
package main
import (
"fmt"
"github.com/ppknap/tensor"
)
func dot3x3(a, b [9]int) (res [9]int) {
var (
at = tensor.NewVector(a[:]).Reshape(3, 3)
bt = tensor.NewVector(b[:]).Reshape(3, 3)
)
for i, t := range at.Dot(bt).Destruct() {
res[i] = t.Int()
}
return res
}
func main() {
var (
a = [9]int{10, 20, 30, 40, 50, 60, 70, 80, 90}
b = [9]int{-1, -2, -3, -4, -5, -6, -7, -8, -9}
)
fmt.Printf("Op:\n %v_(3,3) @\n %v_(3,3) =\n %v_(3,3)\n", a, b, dot3x3(a, b))
}Output:
Op:
[10 20 30 40 50 60 70 80 90]_(3,3) @
[-1 -2 -3 -4 -5 -6 -7 -8 -9]_(3,3) =
[-300 -360 -420 -660 -810 -960 -1020 -1260 -1500]_(3,3)
NumPy interoperability
Tensor's binary encoding format is compatible with NPY encoding. Thus, it is possible to use tensor objects in Python and NumPy arrays in Go.
package main
import (
"fmt"
"github.com/ppknap/tensor"
)
func main() {
vec := tensor.NewVector([]string{"Export", "me", "to", "NPY"})
b, err := vec.MarshalBinary()
if err != nil {
panic(err)
}
fmt.Printf("NPY header: %s\n", b[10:67])
}Output:
NPY header: {'descr': '<U6', 'fortran_order': False, 'shape': (4,), }
Error handling
This example demonstrates how one can handle all tensor's internal errors. Note, that this is not a recommended way of using this package since the errors that could be thrown usually indicate invalid input data or broken logic.
package main
import (
"fmt"
"github.com/ppknap/tensor"
)
func main() {
fmt.Printf("Error: %s\n", tensor.Guard(func() {
tensor.Divide(tensor.NewVector([]int{5, 6}), tensor.NewScalar("divisor"))
}))
}Output:
Error: tensor: invalid division on string type
More...
For other examples see GoDoc.
Milestones
This project is still in beta state. Thus, the items on the following list should be treated more like ideas than a roadmap.
- API function set similar to the one provided by numpy's routines.
- BLAS support.
- Masked tensors.
- Support for types defined in math/big package.
- Custom defined types via
Fieldinterface. - Test coverage over 90%.
There are no intentions to support Google App Engine platform since this library heavily utilizes unsafe package.
Contributing
Please feel free to contribute! See the CONTRIBUTING.md file for more info.
Similar projects
There are two notable packages in the Go ecosystem that were created to solve similar problems as this library. Tensor goal is not to provide alternative for them since it focuses on a single mathematical concept where presented ones are parts of larger and more mature computational ecosystems. Thus, they give you better performance in exchange of code readability.
| Project | Description |
|---|---|
| gonum/gonum/mat | Rich and highly optimized matrix library for float64 and complex128 types that provides many useful linear algebra operations. |
| gorgonia/tensor | Generic, N-dimensional array library used as main tensors object source in the excellent machine learning library for Go - Gorgonia. |
Benchmarks
TODO
Versioning
Tensor package uses 0ver for versioning. For the available versions, see the tags on this repository.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Acknowledgments
The API of this project is highly influenced by the great numpy package.

Formed in 2009, the Archive Team (not to be confused with the archive.org Archive-It Team) is a rogue archivist collective dedicated to saving copies of rapidly dying or deleted websites for the sake of history and digital heritage. The group is 100% composed of volunteers and interested parties, and has expanded into a large amount of related projects for saving online and digital history.

