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 ¶
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) Dimensionality ¶
func (D1) Dimensions ¶
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) Dimensionality ¶
func (D2) Dimensions ¶
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) Dimensionality ¶
func (D3) Dimensions ¶
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) Dimensionality ¶
func (D4) Dimensions ¶
type Map ¶
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 ¶
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 ¶
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.
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