diff options
| author | gingerBill <bill@gingerbill.org> | 2021-10-28 00:49:09 +0100 |
|---|---|---|
| committer | gingerBill <bill@gingerbill.org> | 2021-10-28 00:49:09 +0100 |
| commit | 5b7f27316509344e9c20f2901c8ad867e51a08a7 (patch) | |
| tree | 359c4ecb45f8585a3c2663f93d4c31a6841507a4 /examples | |
| parent | 90d587df13c31e0c1c10d73287a3368df7cfad00 (diff) | |
Add `matrix_type` to demo.odin
Diffstat (limited to 'examples')
| -rw-r--r-- | examples/demo/demo.odin | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index a035a0f5e..bc543b823 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -2203,6 +2203,212 @@ arbitrary_precision_maths :: proc() { print_bigint("\nLCM of random prime A and random number B (in base 36): ", d, 36) } +matrix_type :: proc() { + fmt.println("\n# matrix type") + // A matrix is a mathematical type built into Odin. It is a regular array of numbers, + // arranged in rows and columns + + { + // The following represents a matrix that has 2 rows and 3 columns + m: matrix[2, 3]f32 + + m = matrix[2, 3]f32{ + 1, 9, -13, + 20, 5, -6, + } + + // Element types of integers, float, and complex numbers are supported by matrices. + // There is no support for booleans, quaternions, or any compound type. + + // Indexing a matrix can be used with the matrix indexing syntax + // This mirrors othe type usages: type on the left, usage on the right + + elem := m[1, 2] // row 1, column 2 + assert(elem == -6) + + + // Scalars act as if they are scaled identity matrices + // and can be assigned to matrices as them + b := matrix[2, 2]f32{} + f := f32(3) + b = f + + fmt.println("b", b) + fmt.println("b == f", b == f) + + } + + { // Matrices support multiplication between matrices + a := matrix[2, 3]f32{ + 2, 3, 1, + 4, 5, 0, + } + + b := matrix[3, 2]f32{ + 1, 2, + 3, 4, + 5, 6, + } + + fmt.println("a", a) + fmt.println("b", b) + + c := a * b + #assert(type_of(c) == matrix[2, 2]f32) + fmt.tprintln("c = a * b", c) + } + + { // Matrices support multiplication between matrices and arrays + m := matrix[4, 4]f32{ + 1, 2, 3, 4, + 5, 5, 4, 2, + 0, 1, 3, 0, + 0, 1, 4, 1, + } + + v := [4]f32{1, 5, 4, 3} + + // treating 'v' as a column vector + fmt.println("m * v", m * v) + + // treating 'v' as a row vector + fmt.println("v * m", v * m) + + // Support with non-square matrices + s := matrix[2, 4]f32{ // [4][2]f32 + 2, 4, 3, 1, + 7, 8, 6, 5, + } + + w := [2]f32{1, 2} + r: [4]f32 = w * s + fmt.println("r", r) + } + + { // Component-wise operations + // if the element type supports it + // Not support for '/', '%', or '%%' operations + + a := matrix[2, 2]i32{ + 1, 2, + 3, 4, + } + + b := matrix[2, 2]i32{ + -5, 1, + 9, -7, + } + + c0 := a + b + c1 := a - b + c2 := a & b + c3 := a | b + c4 := a ~ b + c5 := a &~ b + + // component-wise multiplication + // since a * b would be a standard matrix multiplication + c6 := hadamard_product(a, b) + + + fmt.println("a + b", c0) + fmt.println("a - b", c1) + fmt.println("a & b", c2) + fmt.println("a | b", c3) + fmt.println("a ~ b", c4) + fmt.println("a &~ b", c5) + fmt.println("hadamard_product(a, b)", c6) + } + + { // Submatrix casting square matrices + // Casting a square matrix to another square matrix with same element type + // is supported. + // If the cast is to a smaller matrix type, the top-left submatrix is taken. + // If the cast is to a larger matrix type, the matrix is extended with zeros + // everywhere and ones in the diagonal for the unfilled elements of the + // extended matrix. + + mat2 :: distinct matrix[2, 2]f32 + mat4 :: distinct matrix[4, 4]f32 + + m2 := mat2{ + 1, 3, + 2, 4, + } + + m4 := mat4(m2) + assert(m4[2, 2] == 1) + assert(m4[3, 3] == 1) + fmt.println("m2", m2) + fmt.println("m4", m4) + fmt.println("mat2(m4)", mat2(m4)) + assert(mat2(m4) == m2) + } + + { // Casting non-square matrices + // Casting a matrix to another matrix is allowed as long as they share + // the same element type and the number of elements (rows*columns). + // Matrices in Odin are stored in column-major order, which means + // the casts will preserve this element order. + + mat2x4 :: distinct matrix[2, 4]f32 + mat4x2 :: distinct matrix[4, 2]f32 + + x := mat2x4{ + 1, 3, 5, 7, + 2, 4, 6, 8, + } + + y := mat4x2(x) + fmt.println("x", x) + fmt.println("y", y) + } + + // TECHNICAL INFORMATION: the internal representation of a matrix in Odin is stored + // in column-major format + // e.g. matrix[2, 3]f32 is internally [3][2]f32 (with different a alignment requirement) + // Column-major is used in order to utilize SIMD instructions effectively on modern hardware + // + // Unlike normal arrays, matrices try to maximize alignment to allow for the (SIMD) vectorization + // properties whilst keeping zero padding (either between columns or at the end of the type). + // + // Zero padding is a compromise for use with third-party libraries, instead of optimizing for performance + // + // Currently, matrices are limited to a maximum of 16 elements (rows*columns), and a minimum of 1 element. + // This is because matrices are stored as values (not a reference type), and thus operations on them will + // be stored on the stack. Restricting the maximum element count minimizing the possibility of stack overflows. + + // Built-in Procedures (Compiler Level) + // transpose(m) + // transposes a matrix + // outer_product(a, b) + // takes two array-like data types and returns the outer product + // of the values in a matrix + // hadamard_product(a, b) + // component-wise multiplication of two matrices of the same type + // matrix_flatten(m) + // converts the matrix into a flatten array of elements + // in column-major order + // Example: + // m := matrix[2, 2]f32{ + // x0, x1, + // y0, y1, + // } + // array: [4]f32 = matrix_flatten(m) + // assert(array == {x0, y0, x1, y1}) + // conj(x) + // conjugates the elements of a matrix for complex element types only + + // Built-in Procedures (Runtime Level) (all square matrix procedures) + // determinant(m) + // adjugate(m) + // inverse(m) + // inverse_transpose(m) + // hermitian_adjoint(m) + // matrix_trace(m) + // matrix_minor(m) +} + main :: proc() { when true { the_basics() @@ -2238,5 +2444,6 @@ main :: proc() { or_else_operator() or_return_operator() arbitrary_precision_maths() + matrix_type() } } |