Package shapes provides an algebra for handling shapes

About

Package shapes provides the algebra and machinery for dealing with the metainformation of shapes of a tensor.

Why a shape package?

The shape package defines a syntax and semantics that describes shapes of values.

The goal is:

  • to describe the notion of shape;
  • to implement various automation to work with shapes (example a a tool that verify if shapes of different inputs are compatible to be used with one operator)

What is a Shape?

A shape is a piece of meta-information that tells you something about a tensor.

A rank-2 tensor is also commonly known as a matrix (mathematicians and physicists, please bear with the inaccuracies and informalities).

Example

Let's consider the following matrix:

⎡1  2  3⎤
⎣4  5  6⎦

We can describe this matrix by saying "it's a matrix with 2 rows and 3 columns". We can write this as (2, 3).

(2, 3) is the shape of the matrix.

This is a very convenient way of describing N-dimensiional tensors. We don't have to give the dimensions names like "layer", "row" or "column". We would rapidly run out of names! Instead, we just index them by their number. So in a 3 dimensional shape, instead of saying "layer", we say "dimension 0". In a 2 dimensional shape, "row" would be "dimension 0".

Components of a Shape

Given a shape, let's explore the components of the shape:

 +--+--+--------- size
 v  v  v
(2, 3, 4) <------ shape
 ^̄  ^̄  ^̄
 +--+--+--------- dimension/axis

Each "slot" in a shape is called a dimension/axis. The number of dimensions in a shape is called a rank (though confusingly enough, in the Gorgonia family of libraries, it's called .Dims()). There are 3 slots in the example, so it's a 3 dimensional shape. Each number in a slot is called the size of the dimension. When refering to them by their number, the preferred term is to use "axis". So, axis 1 has a size of 3, therefore, the first dimension is of size 3.

To use the traditional named dimensions - recall in this instance, that dimension 1 is "rows" - We say there are 3 rows.

Shape Expr: Syntax

The primary data structure that the package provides is the shape expression. A shape expression is given by the following BNF

<shape>    ::= <unit>| "("<integer>",)" | "("<integer>","<shape>")" |
               "("<shape>","<integer>")" | "("<variable>",)" |
               <binaryOperationExpression> | <nameOfT>

<integer>  ::= <digit> [ <integer> ]
<digit>    ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
<unit>     ::= "()"
<variable>  ::= ...
<binaryOperationExpression>  ::= "("<variable> <binop> <integer>",)" |
                       "("<variable> <binop> <variable>",) |
                       "("<integer> <binop> <variable>",)"
<binop>   ::= + | *

<expression> ::= <shape> | I n <expression> | D <expression |
                 K <expression> | Σ <expression> | Π <expression> |
                 <variable> | <expression → <expression> |
                 (<expression> → <expression>) @ <expression> // TODO
T ::= (I n E,) | (D E,) | (Σ E,) | (Π E,) // TODO
A compact BNF

The original design for the language of shapes was written in a compact BNF. This was expanded by Olivier Wulveryck into something that traditional computer scientists are more familiar with.

Here, the original compact BNF is preserved.

E ::= S | I n E | D E | K E | Σ E | Π E | a | E -> E | (E -> E) @ E
S ::= () | (n,) | (n, S) | (S, n) | (a,) | B | T
T ::= (I n E,) | (D E,) | (Σ E,) | (Π E,)
B ::=  (a O n,) | (a O b,) | (n O a,)
O ::= + | ×
n,m ::= ℕ
a,b ::= variables

The BNF might be brief, but it is dense, so let's break it down.

Primitive Shape Construction

<shape>    ::= <unit>| "("<integer>",)" | "("<integer>","<shape>")" |
               "("<shape>","<integer>")" | "("<variable>",)" |
               <binaryOperationExpr> | <nameOfT>

What this snippet says is: a shape (<shape>) is one of: the four possible definitions of a shape:

  1. <unit> - This is the shape of scalar values. () is pronounced "unit".
  2. "("<integer>",)" - <integer> is any positive number. Example of a shape: (10,).
  3. "("<integer>","<shape>")" - an <interer> folowwed by another <shape>. Example: (8, (10,)).
  4. "("<shape>","<integer>")" - a <shape> followed by another <integer>. Example: ((8, (10,)), 20).

From the snippet, we have generated 4 examples of shapes: (), (10,), (8, (10,)) and ((8, (10,)), 20). This isn't how we normally write shapes. We would normally write them as (10,), (8, 10) and (8, 10, 20). So what's the difference?

In fact, the following are equivalent;

  • (8, (10,)) = (8, 10)
  • ((8, (10,)), 20) = ((8, 10), 20) = (8, (10, 20)) = (8, 10, 20)

What this says is that the primitive shape construction is associative. This is useful as we can now omit the additional parentheses.

On <unit>

The unit () is particularly interesting. In a while we'll see why it's called a "unit".

For now, given the associativity rules, what would (10, ()) be equivalent to? One possible answer is (10, ) - afterall, we're just removing the internal parentheses. Another possible answer is (10, 1).

TODO write more.

Introducing Variables

Now, let us focus, once again on line 2 of the BNF, but on the latter parts:

<shape> ::= ... | (<variable>,) | ...

What this says is that you can create a <shape> using a variable. I'll use x and y for real variables.

Example: (x,) is a shape. Combining this rule with the rules from above, we can see that (x, y) is also a valid shape. So is (10, x) or (x, 10)

To recap using the examples we have seen so far, these are exammples of valid shapes:

  • (x,)
  • (x, 10)
  • (10, x)
  • (10, 20, x)
  • (10, x, 20)

Introducing Binary Operations

In the following snippet (still on line 2 of the BNF), this is introduced:

<shape> ::= ... | <binaryOperationExpression> | ...

And <binaryOperationExpression> is defined in the following line as:

<binaryOperationExpr>  ::= "("<variable> <binop> <integer>",)" |
                       "("<variable> <binop> <variable>",) |
                       "("<integer> <binop> <variable>",)"

What this says is any valid <binaryOperationExpr> is also a valid <shape>.

<binop> is defined as:

<binop>   ::= + | *

That is, a valid mathematical operation is a addition or a multiplication.

So what line 3 of the BNF says is that these are valid shapes:

  • (x + 10,)
  • (x + y,)
  • (10 + x,)

An astute reader will observe that "("<integer> <binop> <integer>")" (example: (10 × 20,)) isn't allowed. The reasoning is clear - if you know ahead of time what the resulting shape will be, don't put a mathematical expression in. Note that though there is a restriction in the fomal language, this is not enforced by the package machinery.

Recap 1

To recap, these are all examples valid shapes:

  • ()
  • (10,)
  • (10, 20)
  • (x,)
  • (x, 10)
  • (10, x)
  • (x, y)
  • (x+20,)
  • (x×y,)
  • (x+20, 10)
  • (10, x×y)

We wil leave the last part of the definition of S (S ::= ... | T) to after we've introduced the notion of expressions.

Shape Expr: Semantics

\frac{}{E_1 \rightarrow E_2}\ \frac{E_1 \rightarrow E_2 \ \ \ \ \vdash E_3: S}{E_1 \rightarrow E_2  @ E_3 \Rightarrow  {S/a} E_2}

TODO: write more

Why So Complicated?

Why introduce all these complicated things? We introduce these complicated things because we want to do things with shape expressions.

It is a System of Constraints

Ideally, the shape expression should be enough to tell you what an operation does to the shape of its inputs.

Consider for example, a shape expression that is the following:

(a, b) → (b, c) → (a, c)

What does this expression say? It says the operation takes a matrix with shape (a, b), and then takes another matrix with the shape (b, c), finally, it returns a matrix of shape (a, c).

This simple expression contains a lot of information:

  • The inputs are matrices only.
  • The inner dimension of the first input must be the same as the outer dimension of the second input.
  • The output is a matrix only, not of any other rank.
  • The matching dimensions disappear.

In fact, there is precisely one operation that is described by this expression: Matrix Multiplication.

Here we see one of the functions of the shape expression: it's to provide constraints to the inputs. e.g. the inputs must be matrices; the matching dimensions; etc.

A Second Example

Here's another example. Consider this shape expression, can you guess what it does?

(a, b) → (a, c) → (a, b+c)
Amswer

It's a concatenation on axis 1. A concrete example is given:

t :=
shape: (2, 3)
⎡0  1  2⎤
⎣3  4  5⎦

u :=
shape: (2, 2)
⎡100  200⎤
⎣300  400⎦

Concat(1, t, u) =
shape: (2, 5)
⎡  0    1    2  100  200⎤
⎣  3    4    5  300  400⎦

It is a System of Evolving Constraints

The shape expression system can not only define constraints, it can also evolve them.

Going back to the matrix multiplication example, now let's extend it.

(a, b) → (b, c) → (a, c) @ (2, 3)

When this is run through the interpreter of the expression, the result will be the following shape expression:

(3, c) → (2, c)

The constraints have now evolved.

Recall that the @ symbol is an application of a function to an input. So when given an input matrix of a known size - (2, 3), we can evolve the constraints, so the next input will only require one check instead of two.

Similar Resources

generativeart is a Go package to generate many kinds of generative art.

generativeart is a Go package to generate many kinds of generative art.

generativeart is a Go package to generate many kinds of generative art. The goal is to collect some excellent generative art (implemented in R or Processing), and rewrite them in Go again

Dec 29, 2022

golang package to find the K most dominant/prominent colors in an image

golang package to find the K most dominant/prominent colors in an image

prominentcolor Find the K most dominant colors in an image The Kmeans function returns the K most dominant colors in the image, ordered in the order o

Nov 7, 2022

Go package captcha implements generation and verification of image and audio CAPTCHAs.

Go package captcha implements generation and verification of image and audio CAPTCHAs.

Package captcha ⚠️ Warning: this captcha can be broken by advanced OCR captcha breaking algorithms. import "github.com/dchest/captcha" Package captch

Dec 30, 2022

openGL Have Fun - A Go package that makes life with OpenGL enjoyable.

glhf openGL Have Fun - A Go package that makes life with OpenGL enjoyable. go get github.com/faiface/glhf Main features Garbage collected OpenGL obje

Jan 1, 2023

Procedural texture generation package.

Procedural texture generation package.

Texture Generation A package for the procedural generation of textures. Based on the ideas contained in the Bryce 3D deep texture editor. More example

Sep 8, 2022

asciigrid is a Go package that implements decoder and encoder for the Esri ASCII grid format, also known as ARC/INFO ASCII GRID.

asciigrid asciigrid is a Go package that implements decoder and encoder for the Esri ASCII grid format, also known as ARC/INFO ASCII GRID. Install go

Jul 3, 2022

package for convert DataURLs to image

convert base64 DataURLs to image

Oct 18, 2021

A Go package converting a monochrome 1-bit bitmap image into a set of vector paths.

A Go package converting a monochrome 1-bit bitmap image into a set of vector paths.

go-bmppath Overview Package bmppath converts a monochrome 1-bit bitmap image into a set of vector paths. Note that this package is by no means a sophi

Mar 22, 2022

Package qrcode implements a QR Code encoder

A matrix barcode, Arbitrary content may be encoded, with URLs being a popular choice

Nov 1, 2021
Related tags
The android-go project provides a platform for writing native Android apps in Go programming language.
The android-go project provides a platform for writing native Android apps in Go programming language.

android-go The android-go project aims to provide a platform (namely an SDK) for writing native Android apps in Go programming language. All things he

Jan 5, 2023
Provides a method to create thumbnails from provided images.

Thumbnail Generation Package for Go This package provides method to create thumbnails from provided images. Installation Use to go command: $ go get g

Aug 31, 2022
Open-in-linear - A tool provides a shortcut to opening a linear issue in the desktop app or browser

This tool provides a shortcut to opening a linear issue in the desktop app or browser.

Jan 25, 2022
A pure Go package for coordinate transformations.

WGS84 A pure Go package for coordinate transformations. go get github.com/wroge/wgs84 Usage east, north, h := wgs84.LonLat().To(wgs84.ETRS89UTM(32)).R

Nov 25, 2022
Go package for fast high-level image processing powered by libvips C library

bimg Small Go package for fast high-level image processing using libvips via C bindings, providing a simple programmatic API. bimg was designed to be

Jan 2, 2023
Go bindings for GStreamer (retired: currently I don't use/develop this package)

Retired. I don't use/develop this package anymore. Go bindings for GStreamer at a very early stage of maturity. This package is based on GLib bindings

Nov 10, 2022
Imaging is a simple image processing package for Go
Imaging is a simple image processing package for Go

Imaging Package imaging provides basic image processing functions (resize, rotate, crop, brightness/contrast adjustments, etc.). All the image process

Dec 30, 2022
Go package for decoding and encoding TARGA image format

tga tga is a Go package for decoding and encoding TARGA image format. It supports RLE and raw TARGA images with 8/15/16/24/32 bits per pixel, monochro

Sep 26, 2022
Go package for computer vision using OpenCV 4 and beyond.
Go package for computer vision using OpenCV 4 and beyond.

GoCV The GoCV package provides Go language bindings for the OpenCV 4 computer vision library. The GoCV package supports the latest releases of Go and

Jan 1, 2023
Go Perceptual image hashing package

goimagehash Inspired by imagehash A image hashing library written in Go. ImageHash supports: Average hashing Difference hashing Perception hashing Wav

Jan 3, 2023