dimensions

package
v2.16.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 24, 2024 License: MIT Imports: 2 Imported by: 0

Documentation

Overview

Package dimensions implements an interface and concrete types for indexing a matrix of values along an arbitrary number of dimensions.

The concrete implementations are exposed for use by performance-sensitive code.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type D

type D interface {
	// Dimensions returns itself. If the implementation is heavy, it should
	// return a new D constructed with [New].
	Dimensions() D

	// Index computes an index calculated from the offsets along each axis.
	//
	// If any individual offset is out of bounds, it is wrapped round, modulo
	// the length along that axis. The caller must ensure that dest has a
	// length >= Dimensionality.
	Index(offsets ...int) int

	// Offsets calculates the offset along each axis identified by the given
	// index. The results are stored in dest. If the index is out of bounds,
	// it is wrapped round modulo Size. The caller must ensure that dest has
	// a length >= Dimensionality.
	Offsets(dest []int, idx int)

	// Contains returns true if each provided offset is less than the length
	// along its respective axis.
	//
	// As a special case, if len(offsets) is greater than the Dimensionality of
	// the matrix, an element is still considered to be contained if the offset
	// is zero. For example, (2, 4, 0) is considered to be contained by a
	// 2-dimensional matrix iff (2, 4) is also contained.
	Contains(offsets ...int) bool

	// Size returns the number of unique indexes, from 0 to size minus 1
	// inclusive, that can be used to obtain an Index. This is also the unit
	// volume of the matrix.
	Size() int

	// Dimensionality returns the number of dimensions e.g. 2 for "2D".
	Dimensionality() int

	// Length returns the length along the specified zero-indexed axis. For
	// example, Length(2) returns the depth in the third axis
	// (z axis).
	//
	// As a special case, the value of the ASCII characters in each of the
	// string "xyzw" may be used to refer to the dimensions 0, 1, 2 and 3,
	// respectively. For example, Length('z') == Length(2). Case is ignored.
	//
	// The result is undefined if idx is less than zero. If idx is >=
	// Dimensionality, returns zero.
	Length(idx int) int

	// Lengths returns the lengths along each axis. The results are stored in
	// dest. If dest is not large enough, the results are truncated.
	Lengths(dest []int)
}

D is the interface implemented by an element that represents the dimensionality (e.g. 2D, 3D, etc.) and size (in each axis, e.g. x, y, z) of a matrix of values.

It implements a bidirectional mapping from a single integer index to a slice of offsets along each axis. The mapping assumes row-major order.

In general, D is treated as immutable and may be copied, but, for the sake of robustness, copies should be made using the Dimensions method.

func New

func New(sizes ...int) D

New returns a new element implementing the dimensions interface D.

In performance-sensitive code, this may be cast into the concrete types D1, D2, D3, D4, for 1-, 2-, 3-, 4-dimensional implementations, respectively.

5-dimensional and higher implementations are supported, but the concrete type is not exposed. Zero dimensions, dimensions of size zero, and dimensions higher than 64 are not supported and will panic.

type D1

type D1 [1]int

D1 is a 1-dimensional implementation of the D interface. In most cases, this is initialised by calling New with 1 argument. Performance sensitive code may cast D to this type.

func (D1) Contains

func (r D1) Contains(offsets ...int) bool

func (D1) Dimensionality

func (r D1) Dimensionality() int

func (D1) Dimensions

func (r D1) Dimensions() D

func (D1) Index

func (r D1) Index(offsets ...int) int

func (D1) Length

func (r D1) Length(idx int) int

func (D1) Lengths

func (r D1) Lengths(dest []int)

func (D1) Offsets

func (r D1) Offsets(dest []int, idx int)

func (D1) Size

func (r D1) Size() int

type D2

type D2 [2]int

D2 is a 2-dimensional implementation of the D interface. In most cases, this is initialised by calling New with 2 arguments. Performance sensitive code may cast D to this type.

func (D2) Contains

func (r D2) Contains(offsets ...int) bool

func (D2) Dimensionality

func (r D2) Dimensionality() int

func (D2) Dimensions

func (r D2) Dimensions() D

func (D2) Index

func (r D2) Index(offsets ...int) int

func (D2) Length

func (r D2) Length(idx int) int

func (D2) Lengths

func (r D2) Lengths(dest []int)

func (D2) Offsets

func (r D2) Offsets(dest []int, idx int)

func (D2) Size

func (r D2) Size() int

type D3

type D3 [3]int

D3 is a 3-dimensional implementation of the D interface. In most cases, this is initialised by calling New with 3 arguments. Performance sensitive code may cast D to this type.

func (D3) Contains

func (r D3) Contains(offsets ...int) bool

func (D3) Dimensionality

func (r D3) Dimensionality() int

func (D3) Dimensions

func (r D3) Dimensions() D

func (D3) Index

func (r D3) Index(offsets ...int) int

func (D3) Length

func (r D3) Length(idx int) int

func (D3) Lengths

func (r D3) Lengths(dest []int)

func (D3) Offsets

func (r D3) Offsets(dest []int, idx int)

func (D3) Size

func (r D3) Size() int

type D4

type D4 [4]int // width, height, depth, extent

D4 is a 4-dimensional implementation of the D interface. In most cases, this is initialised by calling New with 4 arguments. Performance sensitive code may cast D to this type.

func (D4) Contains

func (r D4) Contains(offsets ...int) bool

func (D4) Dimensionality

func (r D4) Dimensionality() int

func (D4) Dimensions

func (r D4) Dimensions() D

func (D4) Index

func (r D4) Index(offsets ...int) int

func (D4) Length

func (r D4) Length(idx int) int

func (D4) Lengths

func (r D4) Lengths(dest []int)

func (D4) Offsets

func (r D4) Offsets(dest []int, idx int)

func (D4) Size

func (r D4) Size() int

type Map

type Map interface {
	D
	Original() D
	MapOffsets(dest []int, source ...int)
	MapIndex(idx int) int
}

Map describes a new set of dimensions formed by applying a mapping operation to an original set of dimensions. For example, this could be rotation, translation, cropping, mirroring, or different projections of dimensions.

Map itself implements the D interface, but extends it with methods that map offsets and indexes back to the original shape.

MapOffsets describes how to convert offsets on the new shape (the source arguments) back to offsets on the original shape (the dest arguments). len(dest) == original.Dimensionality() and len(offsets) == new.Dimensionality().

MapIndex describes how to convert an index on the new shape (the idx argument) back to an index on the original shape (the return value).

func Crop

func Crop(target D, startIdx int, lengths ...int) Map

Crop returns a Map of a sub-region of the target shape.

It is specified by identifying the index of a start point on the target, and the lengths in each dimension.

If the specified length in any direction would take an offset further than the target length in that respective dimension, then it is cropped to the dimension boundaries. Lengths must be positive.

type Mapper

type Mapper struct {
	Shapes  func(original D) D
	Offsets func(original, new D) func(dest []int, source ...int)
}

Mapper can be used to create a Map for any shape. If a Map describes a mapping between two specific shapes, a Mapper describes a mapping between two types of shapes.

Example
package main

import (
	"fmt"

	"github.com/tawesoft/golib/v2/ds/matrix/dimensions"
)

func main() {
	// This example maps X,Y coordinates onto faces of a 3D box (size 4x3x6),
	// with the 4x3 side on the front and back, 4x6 sides on the top and
	// bottom, and 3x6 on the left and right sides.

	cube := dimensions.New(4, 3, 6)
	var cubeOffsets [3]int

	// define how to map the bottom of any cube to a 2D grid
	bottomMap := dimensions.Mapper{
		Shapes: func(target dimensions.D) dimensions.D {
			return dimensions.New(
				target.Length(0), // X
				target.Length(2), // Z
			)
		},
		Offsets: func(original, new dimensions.D) func(dest []int, source ...int) {
			return func(dest []int, source ...int) {
				dest[0] = source[0]
				dest[1] = original.Length(1) - 1
				dest[2] = original.Length(2) - 1 - source[1] // backwards
			}
		},
	}

	// map the bottom of *this specific* cube
	cubeBottom := bottomMap.Bind(cube)

	// For this example, we'll iterate over x and z for the 4x6 face.
	fmt.Println("Bottom:")
	for z := 0; z < cubeBottom.Length(1); z++ {
		for x := 0; x < cubeBottom.Length(0); x++ {
			// convert (x, z) offsets  on the face to offsets on the target
			cubeBottom.MapOffsets(cubeOffsets[:], x, z)

			fmt.Printf("(%d, %d) -> (%d, %d, %d)\n",
				x, z, cubeOffsets[0], cubeOffsets[1], cubeOffsets[2])
		}
	}

	// define how to map the right side of any cube to a 2D grid
	rightMap := dimensions.Mapper{
		Shapes: func(target dimensions.D) dimensions.D {
			return dimensions.New(
				target.Length(1), // Y
				target.Length(2), // Z
			)
		},
		Offsets: func(original, new dimensions.D) func(dest []int, source ...int) {
			return func(dest []int, source ...int) {
				dest[0] = original.Length(0) - 1 // last slice along X axis
				dest[1] = source[0]
				dest[2] = source[1]
			}
		},
	}

	// map the right side of *this specific* cube
	cubeRight := rightMap.Bind(cube)

	// For this example, we'll iterate over indexes 0 .. 18 for the 3x6 face.
	fmt.Println("\nRight:")
	for idx := 0; idx < cubeRight.Size(); idx++ {
		// convert indexes on the face to indexes on the target
		cubeIdx := cubeRight.MapIndex(idx)

		fmt.Printf("%d -> %d\n", idx, cubeIdx)
	}

}
Output:

Bottom:
(0, 0) -> (0, 2, 5)
(1, 0) -> (1, 2, 5)
(2, 0) -> (2, 2, 5)
(3, 0) -> (3, 2, 5)
(0, 1) -> (0, 2, 4)
(1, 1) -> (1, 2, 4)
(2, 1) -> (2, 2, 4)
(3, 1) -> (3, 2, 4)
(0, 2) -> (0, 2, 3)
(1, 2) -> (1, 2, 3)
(2, 2) -> (2, 2, 3)
(3, 2) -> (3, 2, 3)
(0, 3) -> (0, 2, 2)
(1, 3) -> (1, 2, 2)
(2, 3) -> (2, 2, 2)
(3, 3) -> (3, 2, 2)
(0, 4) -> (0, 2, 1)
(1, 4) -> (1, 2, 1)
(2, 4) -> (2, 2, 1)
(3, 4) -> (3, 2, 1)
(0, 5) -> (0, 2, 0)
(1, 5) -> (1, 2, 0)
(2, 5) -> (2, 2, 0)
(3, 5) -> (3, 2, 0)

Right:
0 -> 3
1 -> 7
2 -> 11
3 -> 15
4 -> 19
5 -> 23
6 -> 27
7 -> 31
8 -> 35
9 -> 39
10 -> 43
11 -> 47
12 -> 51
13 -> 55
14 -> 59
15 -> 63
16 -> 67
17 -> 71

func Sampler

func Sampler(reorder string, constants ...int) Mapper

Sampler returns a new Mapper that can flip, drop, or reorder dimensions of shapes arbitrarily.

The string argument encodes operations on each dimension and an ordering by the presence, or lack thereof, of a sequence of indexes and modifiers.

The presence of the characters '0'-'9' and 'A'-'F' identify dimensions 0 to 15 on the parent. As syntax sugar, the characters in the string "xyzw" are respectively interchangeable with the characters "0123". Case is ignored in all cases.

A dimension preceded by a negative sign flips or mirrors that dimension, so that instead of being read e.g. left to right, or top to bottom, it is instead read right to left, or bottom to top.

Omitted dimensions are mapped to offset zero along that dimension in the parent. A dimension can be excluded and mapped to a constant offset by instead preceding it with an exclamation mark, in which case it is mapped to the next element in the optional "constants" argument, which encodes a constant integer offset into that dimension.

ASCII whitespace is ignored. The syntax does not support more than 16 dimensions. A dimension may not be referenced twice. May panic with [SwizzleSyntaxError].

For example, given a 2D matrix d2, Reorder(matrix, "yx").Map(d2) returns a Map that rotates the x & y dimensions in d2, turning it from row major order into column major order. Similarly, Reorder(matrix, "-x -y").Map(d2) returns a Map that mirrors the matrix along x and y axes. For some 3D matrix d3, Reorder(matrix, "xy !z", 4).Map(d3) returns a Map that models a 2D slice of d3 along the axis z=4.

func (Mapper) Bind

func (m Mapper) Bind(original D) Map

type SamplerSyntaxError

type SamplerSyntaxError struct {
	Offset     int // byte offset
	Input      string
	Unexpected uint8  // character
	Reason     string // if not unexpected
}

func (SamplerSyntaxError) Error

func (e SamplerSyntaxError) Error() string

func (SamplerSyntaxError) Is

func (e SamplerSyntaxError) Is(err error) bool

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL