• Stars
    star
    140
  • Rank 261,473 (Top 6 %)
  • Language
    Elixir
  • License
    MIT License
  • Created over 8 years ago
  • Updated almost 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

The Tensor library adds support for Vectors, Matrixes and higher-dimension Tensors to Elixir.

Tensor

hex.pm version Build Status

The Tensor library adds support for Vectors, Matrixes and higher-dimension Tensors to Elixir. These data structures allow easier creation and manipulation of multi-dimensional collections of things. One could use them for math, but also to build e.g. board game representations.

The Tensor library builds them in a sparse way.

Vector

A Vector is a one-dimensional collection of elements. It can be viewed as a list with a known length.

iex> use Tensor
iex> vec = Vector.new([1,2,3,4,5])
#Vector-(5)[1, 2, 3, 4, 5]
iex> vec2 = Vector.new(~w{foo bar baz qux})
#Vector-(4)["foo", "bar", "baz", "qux"]
iex> vec2[2]
"baz"
iex> Vector.add(vec, 3)
#Vector-(5)[4, 5, 6, 7, 8]
iex> Vector.add(vec, vec)
#Vector-(5)[2, 4, 6, 8, 10]

It is nicer than a list because:

  • retrieving the length happens in O(1)
  • reading/writing elements to the list happens in O(log n), as maps are used internally.
  • concatenation, etc. is also < O(n), for the same reason.

Vectors are very cool, so the following things have been defined to make working with them a bliss:

  • creating vectors from lists
  • appending values to vectors
  • reverse a vector

When working with numerical vectors, you might also like to:

  • addition of a number to all elements in a vector.
  • elementwise addition of two vectors of the same size.
  • calculate the dot product of two numerical vectors

Matrix

A Matrix is a two-dimensional collection of elements, with known width and height.

These are highly useful for certain mathematical calculations, but also for e.g. board games.

Matrices are super useful, so there are many helper methods defined to work with them.

iex> use Tensor
iex> mat = Matrix.new([[1,2,3],[4,5,6],[7,8,9]],3,3)
#Matrix-(3×3)
┌                          ┐
│       1,       2,       3│
│       4,       5,       6│
│       7,       8,       9│
└                          ┘
iex> Matrix.rotate_clockwise(mat)
#Matrix-(3×3)
┌                          ┐
│       7,       4,       1│
│       8,       5,       2│
│       9,       6,       3│
└                          ┘
iex> mat[0]
#Vector-(3)[1, 2, 3]
iex> mat[2][2]
9
iex> Matrix.diag([1,2,3])
#Matrix-(3×3)
┌                          ┐
│       1,       0,       0│
│       0,       2,       0│
│       0,       0,       3│
└                          ┘

iex> Matrix.add(mat, 2)
#Matrix-(3×3)
┌                          ┐
│       3,       4,       5│
│       6,       7,       8│
│       9,      10,      11│
└                          ┘
iex> Matrix.add(mat, mat)
Matrix.add(mat, mat)
#Matrix-(3×3)
┌                          ┐
│       2,       4,       6│
│       8,      10,      12│
│      14,      16,      18│
└                          ┘

The Matrix module lets you:

  • creating matrices from lists
  • creating an identity matrix
  • creating a diagonal matrix from a list.
  • Transpose matrices.
  • Rotate and flip matrices.
  • Check if a matrix is square?, diagonal?, or symmetric?.
  • creating row- or column matrices from vectors.
  • extract specific rows or columns from a matrix.
  • extract values from the main diagonal.

As well as some common math operations

  • Add a number to all values inside a matrix
  • Multiply all values inside a matrix with a number
  • Matrix Multiplication, with two matrices.
  • the trace operation for square matrices.

Higher-Dimension Tensor

Tensors are implemented using maps internally. This means that read and write access to elements in them is O(log n).

iex> use Tensor
iex> tensor = Tensor.new([[[1,2],[3,4],[5,6]],[[7,8],[9,10],[11,12]]], [3,3,2])
#Tensor(3×3×2)
      1,       2
        3,       4
          5,       6
      7,       8
        9,      10
          11,      12
      0,       0
        0,       0
          0,       0
iex> tensor[1]
#Matrix-(3×2)
┌                 ┐
│       7,       8│
│       9,      10│
│      11,      12│
└                 ┘

Vector and Matrices are also Tensors. There exist some functions that only make sense when used on these one- or two-dimensional structures. Therefore, the extra Vector and Matrix modules exist.

Sparcity

The Vectors/Matrices/Tensors are stored in a sparse way. Only the values that differ from the identity (defaults to nil) are actually stored in the Vector/Matrix/Tensor.

This allows for smaller data sizes, as well as faster operations when peforming on, for instance, diagonal matrices.

Numbers

Tensor uses the Numbers library for the implementations of elementwise addition/subtraction/multiplication etc. This means that you can fill a Tensor with e.g. Decimals or Rationals, and it will Just Work!

It even is the case that Tensor itself implements the Numeric behaviour, which means that you can nest Vectors/Matrices/Tensors in your Vectors/Matrices/Tensors, and doing math with them will still work!! (as long as the elements inside the innermost Vector/Matrix/Tensor follow the Numeric behaviour as well, of course.)

Syntactic Sugar

For Tensors, many sugary protocols and behaviours have been implemented to let them play nicely with other parts of your applications:

Access Behaviour

Tensors have implementations of the Access Behaviour, which let you do:

iex> use Tensor
iex> mat = Matrix.new([[1,2],[3,4]], 2,2)
iex> mat[0]
#Vector-(2)[1, 2]
iex> mat[1][1]
4
iex> put_in mat[1][0], 100
#Matrix-(2×2)
┌                 ┐
│       1,       2│
│     100,       4│
└                 ┘

It is even possible to use negative indices to look from the end of the Vector/Matrix/Tensor!

Enumerable Protocol

Tensors allow you to enumerate over the values inside, using the Enumerable protocol. Note that:

  • enumerating over a Vector will iterate over the values inside,
  • enumerating over a Matrix will iterate over the Vectors that make up the rows of the matrix
  • enumerating over an order-3 Tensor will iterate over the Matrices that make up the 2-dimensional slices of this Tensor,
  • etc...

As there are many other ways to iterate over values inside tensors, functions like Tensor.to_list , Matrix.columns also exist.

There are also functions like Tensor.map, which returns a new Tensor containg the results of this mapping operation. Tensor.map is nice in the way that it will only iterate over the actual values that have a value other than the default, which makes it fast.

If you can think of other nice ways to enumerate over Tensors, please let me know, as these would make great additions to the library!

Collectable Protocol

If you want to build up a Vector from a collection of values, or a Matrix from a collection of Vectors, (or an order-3 tensor from a collection of Matrices, etc), you can do so by harnessing the power of the Collectable protocol.

iex> use Tensor
iex> mat = Matrix.new(0,3)
iex> v = Vector.new([1,2,3])
iex> Enum.into([v,v,v], mat)
#Matrix-(3×3)
┌                          ┐
│       1,       2,       3│
│       1,       2,       3│
│       1,       2,       3│
└                          ┘

Inspect Protocol

The Inspect protocol has been overridden for all Tensors.

  • Vectors are shown as a list with the length given.
  • Matrices are shown in a two-dimensional grid, with the dimensions given.
  • Three-dimensional tensors are shown with indentation and colour changes, to show the relationship of the values inside.
  • Four-dimensional Tensors and higher print their lower-dimension values from top-to-bottom.

FunLand.Reducable Semiprotocol

This is a lightweight version of the Enumerable protocol, with a simple implementation.

    iex> use Tensor
    iex> x = Vector.new([1,2,3,4])
    iex> FunLand.Reducable.reduce(x, 0, fn x, acc -> acc + x end)
    10

Extractable Protocol

This allows you to extract a single element per time from the Vector/Tensor/Matrix. Because it is fastest to extract the elements with the highest index, these are returned first.

    iex> use Tensor
    iex> x = Matrix.new([[1,2],[3,4]], 2, 2)
    iex> {:ok, {item, x}} = Extractable.extract(x)
    iex> item
    #Vector<(2)[3, 4]>
    iex> {:ok, {item, x}} = Extractable.extract(x)
    iex> item
    #Vector<(2)[1, 2]>
    iex> Extractable.extract(x)
    {:error, :empty}

Insertable Protocol

This allows you ti insert a single element per time into the Vector/Tensor/Matrix. Insertion always happens at the highest index location. (The size of the highest dimension of the Tensor is increased by one)

    iex> use Tensor
    iex> x = Matrix.new(0, 2)
    iex> {:ok, x} = Insertable.insert(x, Vector.new([1, 2]))
    iex> {:ok, x} = Insertable.insert(x, Vector.new([3, 4]))
    #Matrix<(2×2)
    ┌                 ┐
    │       1,       2│
    │       3,       4│
    └                 ┘
    >

Efficiency

The Tensor package is completely built in Elixir. It is not a wrapper for any functionality written in other languages.

This does mean that if you want to do heavy number crunching, you might want to look for something else.

However, as Tensor uses as sparse tensor implementation, many calculations can be much faster than you might expect from a terse tensor implementation, depending on your input data.

Installation

The package can be installed by adding tensor to your list of dependencies in mix.exs:

def deps do
  [
    {:tensor, "~> 2.0"}
  ]
end

Changelog

  • 2.0.2 - Bugfix w.r.t. optional dependency FunLand.

  • 2.0.1 - Make FunLand an optional dependency.

  • 2.0.0 - Many changes, including Backwards incompatible ones:

    • Increase version number of Numbers. Backwards-incompatible change, as mult is now used instead of mul for multiplication.
    • Moving Tensor, Vector and Matrix all under the Tensor namespace (so they now are Tensor.Tensor, Tensor.Vector, Tensor.Matrix), to follow the HexPM rules of library management (which is, only use one single top-level module name). Write use Tensor to alias the modules in your code.
    • Also introduces FunLand.Mappable, FunLand.Reducable, Extractable and Insertable protocol implementations.
  • 1.2.0 - Tensor.to_sparse_map, Tensor.from_sparse_map. Also, hidden some functions that were supposed to be private but were not yet.

  • 1.1.0 - Add Matrix.width and Matrix.height functions.

  • 1.0.1 - Made documentation of Matrix.new more clear. Thank you, @wsmoak !

  • 1.0.0 - First stable version.

  • 0.8 - Most functionality has been implemented.

Roadmap

  • Operation to swap any two arbitrary dimensions of a Tensor, a generalized version of Matrix.transpose
  • Improve Tensor inspect output.
  • Move more functionality to Tensor.
  • Add Dyalizer specs to all important methods.
  • Add aliases to common methods of Tensor to:
    • Vector
    • Matrix
  • Ensure that when the identity value is stored, it is not actually stored in a Tensor, so Tensor is kept sparse.
    • Tensor.new
    • Tensor.map
    • Tensor.sparse_map_with_coordinates
    • Tensor.dense_map_with_coordinates
    • Tensor.merge
    • Tensor.merge_with_coordinates
  • Possibility to use any kind of numbers, including custom data types, for Tensor.add, Tensor.sub, Tensor.mul, Tensor.div and Tensor.pow.
  • Write (doc)tests for all public functions.
  • Improve documentation.

More Repositories

1

elixir-type_check

TypeCheck: Fast and flexible runtime type-checking for your Elixir projects.
Elixir
519
star
2

elixir-map_diff

Calculates the difference between two (nested) maps, and returns a map representing the patch of changes.
Elixir
116
star
3

ruby-prop_check

Property Testing library in Ruby
Ruby
87
star
4

elixir-arrays

Well-structured Arrays with fast random-element-access for Elixir, offering a common interface with multiple implementations with varying performance guarantees that can be switched in your configuration.
Elixir
76
star
5

elixir-fun_land

Algebraic Data Types for Elixir: Both functional and fun.
Elixir
69
star
6

elixir-capture_pipe

A pipe-macro for Elixir that allows bare function captures
Elixir
45
star
7

raii_with

A simple library to provide RAII in standard-compliant C99, using raii_with(resource, initializer, destructor) { ... }-syntax:
C
41
star
8

elixir-currying

Currying enables partial function application in Elixir.
Elixir
41
star
9

elixir-rational

Rational number library for Elixir.
Elixir
39
star
10

c_exceptional

A simple Exception-handling library for C99, that uses some fancy macros for true try{...}catch(err){...}finally{...} syntax!
C++
37
star
11

elixir-number

Numbers -- A generic wrapper to use *any* custom Numeric type in Elixir!
Elixir
36
star
12

elixir-specify

A library to create Comfortable, Explicit, Multi-Layered and Well-Documented Specifications for all your configurations, settings and options in Elixir.
Elixir
33
star
13

elixir-blocked

An Elixir-library that helps you to keep track of when hotfixes can be removed by showing compile-time warnings when issues (in your project repository or any other source-code GitHub repository) are closed.
Elixir
29
star
14

elixir-okasaki

Multiple different implementations of efficient functional queues and dequeues for Elixir
Elixir
28
star
15

elixir-revisionair

Keep track of your data structure's revisions, persistence layer agnostic.
Elixir
26
star
16

elixir-rustler_elixir_fun

Calling Elixir or Erlang functions from native code written in Rust
Rust
25
star
17

elixir-sequences

Defines a module containing many common integer sequences (even numbers, odd numbers, primes, factorials, fibonacci, etc)
Elixir
21
star
18

inscryption-secrets-hints

21
star
19

elixir-agarex

An example game for the presentation "Multiplayer Games & Collaborative Editing with Phoenix LiveView" which was written for ElixirConf.EU 2020.
Elixir
21
star
20

js1k_powder_game

JavaScript
19
star
21

cpp-parser_combinators

An example of how to construct a parser combinator library in C++. Focus on simplicity, not efficiency.
C++
18
star
22

elixir-revisionair_ecto

A Revisionair adapter based on Ecto. Allows you to persist and keep track of revisions of your data structures in any of Ecto's supported databases.
Elixir
18
star
23

elixir-tea_vent

Elixir library to do event-dispatching in an Event Sourcing and The Elm Architecture-like way
Elixir
17
star
24

elixir-solution

A Macro-based approach to ease working with ok/error tuples in Elixir
Elixir
17
star
25

elixir-prioqueue

Priority Queues for Elixir.
Elixir
15
star
26

elixir_gen_frp

Elixir
15
star
27

elixir-riak_ecto3

RiakEcto3 is an Elixir Ecto 3 Adapter for the Riak KV database (For Riak KV v 2.0 and upward).
Elixir
13
star
28

Jux

Elixir
12
star
29

elixir_persistent_gen_server

Elixir
11
star
30

ExtremeBytebeats

A collection of bytebeat programs, some of them rather involved.
JavaScript
11
star
31

elixir_complex_num

Complex Numbers for Elixir, wrapping not only floats but _any_ kind of numeric data type.
Elixir
11
star
32

elixir-arrays_aja

Provides an `Arrays` implementation for `Aja`'s `Vector` datatype, which is an implementation of a 'Hickey Trie' Vector written in Elixir.
HTML
8
star
33

rust-overloaded_literals

Rust crate: Overloaded Literals to construct your datatypes without boilerplate and with compile-time validation.
Rust
8
star
34

elixir-orderable

A protocol for making your custom datastructures orderable (for sorting and comparing.).
Elixir
7
star
35

ruby-doctest2

Doctests (documentation testing) for Ruby
Ruby
5
star
36

rust-backdrop_arc

An Arc (atomically reference counted smart pointer) that supports customized dropping strategies using Backdrop.
Rust
5
star
37

LastMail

LastMail is the world's first passive post-mortem message system. It lets you send a good-bye to your friends and contacts, and pass on your (digital) belongings.
PHP
4
star
38

elixir-unicode

The Elixir Unicode package provides functionality to check properties of unicode codepoints, graphemes and strings.
Elixir
4
star
39

elixir_ordered_siblings

Ordered Siblings: Allows reordering (in Ecto) of comments under posts, images under albums, songs under playlists, etc.
Elixir
4
star
40

elixir_guard_safe_modulo

The ridiculous guard-safe implementation for a floored modulo operation.
Elixir
4
star
41

haskell-vary

A fast and user-friendly implementation of variant types (aka open unions, open sum types, coproducts)
Haskell
4
star
42

rust-backdrop

Drop your large or complex Rust objects in the background using Backdrop!
Rust
4
star
43

SimpleRNG

A very simple Xorshift-based RNG, whose goal is to reproduce the same results regardless of platform, language or environment
Haskell
4
star
44

rust-slimmer_box

`SlimmerBox<T>` is a packed alternative to `Box<T>` whose 'fat' pointer is 'slimmer'
Rust
4
star
45

JS-CoinStackBar

A customizable vertical progress bar in the shape of a stack of coins.
JavaScript
3
star
46

elixir-cubdb_nerves_example

An example of using CubDB with Nerves
Elixir
3
star
47

elixir-extractable

A lightweight reusable Extractable protocol for Elixir, allowing extracting elements one-at-a-time from a collection.
Elixir
3
star
48

elixir-fun_landic

Implementations of common Algorithmic Data Types for Elixir, built on top of the `fun_land` interface.
Elixir
3
star
49

elixir-password-bloomex

Example of using a bloom filter to check for prohibited passwords
Elixir
3
star
50

elixir-sets

Sets for Elixir, with a single interface and varying implementations.
Elixir
3
star
51

photoboothy

Nerves Rpi 3 Photobooth
JavaScript
3
star
52

elixir-arrays_rrb_vector

Wraps Rust's `im::Vector`, an immutable Relaxed-Radix-Balanced Trie-based vector, for usage with the Elixir `Arrays` library
HTML
3
star
53

elixir-insertable

A lightweight reusable Insertable protocol for Elixir, allowing inserting elements one-at-a-time into a collection.
Elixir
3
star
54

elixir-benchmarking_then_genserver

A test to benchmark the performance of `Kernel.then/2` when running it in a semi 'real-life' scenario when managing the state of a GenServer
Erlang
2
star
55

c_treat

A proof-of-concept Trait system for C
C
2
star
56

elixir-stream_data-property-example

Example of how I'd like to nest multiple properties together with the stream_data library
Elixir
2
star
57

concurrency_elixir_slides

This repository contains both the code snippets as well as the slides from my presentation "A Winner is You: Concurrency in Elixir"
Elixir
2
star
58

elixir-sliding_window

Elixir 'Sliding Window'
Elixir
2
star
59

alchemud

An (very early, very crude) to write a Multi-User-Dungeon in Elixir
Elixir
2
star
60

rust-bassert

Better assertions for Rust
Rust
2
star
61

python-multiple_indexed_collection

A collection type for arbitrary objects, that indexes them based on (a subset of) their properties.
Python
2
star
62

rust-naperian

(Experimental) Rust implementation of the paper 'APLicative programming using Naperian functors'
Rust
2
star
63

EpicAuth

Epic! Auth!
Ruby
1
star
64

cc_freeops

An implementation of automatic free binary operator generation when their respective compound operators are known.
Forth
1
star
65

elixir-test-benchmrking_then

A test repo to benchmark the overhead of Kernel.then/2
Elixir
1
star
66

NoMoreOversleeps

Alarm software designed to help polyphasic sleepers catch oversleeps and doze-offs during adaptation by monitoring computer use
Java
1
star
67

elixir-coerce

Automatic coercion of types that can be promoted to each-other for Elixir.
Elixir
1
star
68

elixir-iter

Iterators for Elixir datastructures
Elixir
1
star
69

cpp-traits-with-variants

Example of how to implement Traits in C++ that also work when constructing a collection of trait-implementing objects.
C++
1
star
70

okasaki_benchmark

Elixir
1
star
71

cpp-thunk

Experimental code to do lazy (i.e. on-demand) evaluation of values in C++
C++
1
star
72

elixir-enum_benchmark_example

Microbenchmark comparing the Elixir iteration abstractions for, enum and iter
Elixir
1
star
73

Haskell-sound-playing

A simple example of how to use the SDL2 Haskell bindings to play sound files (as a complete Stack setup with dependencies, because that was most of the hassle)
Haskell
1
star
74

elixir_online-game

A proof-of-concept online game, to test scalability of having many concurrent player-states updating.
Elixir
1
star
75

ifs_zoom

W-M's Bachelor Project about IFS zooming
HTML
1
star
76

elixir-experimental_comparable

An experimental implementation of a possible Comparable protocol for Elixir.
Elixir
1
star
77

haskell-snek

A simple implementation of Snake. Runs in a terminal
Haskell
1
star
78

roc-bf_example

A simple (and incomplete) example of a BrainFukc interpreter in the Roc programming language.
LLVM
1
star
79

symmath

Elixir
1
star
80

rust-polars_s3

POC to write to Object Stores like S3 with Polars
Rust
1
star
81

elixir_calendrical

Elixir
1
star
82

c_hash_map

A very simple HashMap-implementation in C
C
1
star
83

riak-cluster-test

Repository of code about running a Riak cluster using docker
1
star
84

presentation-communicating_between_ruby_and_elixir

Presentation on how you can communicate between a separately running Ruby system and Elixir system, as we do it in Planga.io
JavaScript
1
star
85

haskell-MonotonicityTypes

An implementation of 'Sfuns', functions that keep track of their monotonicity, from the Monotonicity Types paper
HTML
1
star
86

RUG-WebEngineering-Elm

Presentation + Sample project for the Elm (and Sass) tutorial.
JavaScript
1
star