Phantom-algebra is a pure OCaml library implementing strongly-typed small tensors with dimensions 0 ≤ 4, rank ≤ 2, and limited to square matrices.
It makes it possible to manipulate vector and matrix expressions with an uniform notation while still catching non-sensical operations at compile time
For instance, this extract is valid
open Phantom_algebra.Core
let v = vec3 1. 2. 3.
let w = vec3 3. 2. 1.
let u = scalar 2. + cross (v + w) (v - w)
let rot = rotation u v 1.
let r = w + rot * vbut adding a vector to a matrix is not, and yields a type error:
v + rotType errors tend to be quite long to say the least, but individual type of scalars, vectors and matrices are much simpler. However, the size of the type of higher order function may increase exponentially due to the exotic type construction used internally.
Phantom-algebra is inspired by GLSL conventions:
let v = vec2 0. 1. + scalar 1. (* = (1. 2.) *)x * y is interpreted as:
x or y is a scalarx or y is a matrixx and y are a vector)the cross-product of two 2d vectors yields a scalar whereas the cross-product of two 3d vectors yields a 3d pseudo-vectors. (other cross-product are type errors), for instance
cross (vec2 1. 1.) (vec2 (-1.) 1.) + vec4 1 0. 0. 0. = vec4 3. 2. 2. 2.Indices are also-strongly typed, trying to access a index beyond the tensor dimension yields a type error.
let v = vec2 2. 3.
let fine = v.%(x')
let wrong = v.%(z')
let m = mat2 v v
let fine = m.%(xy')
let also_wrong = m.%(zx')
let wrong_rank_this_time = m.%(x')' suffix to avoid shadowing: either x', y', z' and w', r', g', b', a'ors', t', p'andq'`.Similarly, slicing a rank k tensor with a rank n index yields a rank k-n tensor of the same dimension, e.g
let e1 = (vec2 1. 0.)
let id = mat2 e1 (vec2 0. 1.)
let e1' = id.%[x'] (* this is the first row of the id matrix *)
let zero = id.%[xy']Swizzling is supported: dim indices can be combined with the & operator to yield an objet of r+1 rank:
let v = vec4 0. 1. 2. 3.
let w = v.%[w'&z'&'y&'x] (* slicing a vector yields a scalar,
and 4 scalars grouped together become a vector *)
;; w = vec4 3. 2. 1. 0.
let mat = eye d2
let s = mat.%[y'&x']
(* we are reversing the rows, and obtaining a new matrix*)
;; s = mat2 (vec2 0. 1.) (vec2 1. 0.) norm2 v = (v|*|v)Math module let v = Math.cos (vec2 1. 2.) let id = eye d2
let rxy t = rotation (vec3 1. 0. 0.) (vec3 0. 1. 0.) t
let id = diag (vec3 1. 1. 1.) ;; exp (mat2 (0. 1.) (0. -1) ) = rxy 1. let v = scalar 0. |+| vec2 1. 0. |+| scalar 1.
let w = vec4' (scalar 1.)