Skip to content

Commit

Permalink
Add recipe for infrared.
Browse files Browse the repository at this point in the history
Signed-off-by: helehex <helehex@gmail.com>
  • Loading branch information
helehex committed Dec 11, 2024
1 parent 2013bac commit cf19a83
Show file tree
Hide file tree
Showing 5 changed files with 163 additions and 0 deletions.
30 changes: 30 additions & 0 deletions recipes/infrared/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
Infrared is a geometric algebra library for Mojo.

Geometric algebras are clifford algebras in the context of geometry.
It's an alternative paradigm to linear algebra that uses 'multivectors' instead of matrices.
Multivectors can represent geometric objects, and using the 'geometric product', they can be multiplied together.

With infrared, you can generate product tables of arbitrary signature, and parameterize multivectors.
Multivectors are also parameterized on arbitrary basis masks, to avoid unnecessary overhead.

example:
```
alias sig = Signature(2, 0, 1)
var mv = Multivector[sig, sig.vector_mask()](2.0, -1.0)
```

Infrared has no dependecies other than max/mojo

Developers can use infrared to explore geometric algebra,
or as a mathematical abstraction over all forms of geometry
(such as projective, conformal, spacetime, dimension agnostric, etc.)

I'm accepting contributions, but haven't made a contributors guide yet.

Some issues and areas of work include:
- performance improvements, signature generation could use bitwise operations
- constructors for geometric objects and a better model for initializing multivectors
- better basis masking, currently uses a list of bools
- examples and benchmarks

If you want to reach out, you can email me at helehex@gmail.com, or message me on discord (my alias in the modular server is ghostfire)
Binary file added recipes/infrared/avatar.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added recipes/infrared/image.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
40 changes: 40 additions & 0 deletions recipes/infrared/recipe.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
context:
version: "0.1.0"

package:
name: "infrared"
version: ${{ version }}

source:
- git: https://github.com/helehex/infrared.git
rev: 1776092af17ce25af4d3c1273bee9974a4bc66c4

build:
number: 0
script:
- mojo package src -o ${{ PREFIX }}/lib/mojo/infrared.mojopkg
requirements:
host:
- max
run:
- ${{ pin_compatible('max') }}

tests:
- script:
- if: unix
then:
- mojo run test.mojo
files:
recipe:
- test.mojo

about:
homepage: https://github.com/helehex/infrared
license: MIT
license_file: LICENSE
summary: A geometric algebra library for mojo.
repository: https://github.com/helehex/infrared

extra:
maintainers:
- helehex
93 changes: 93 additions & 0 deletions recipes/infrared/test.mojo
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
from testing import assert_true, assert_false, assert_equal, assert_not_equal
from infrared.algebra import *


def main():
test_eq()
test_ne()
test_subspace_constructor()
test_getattr()
test_normalized()
test_add()
test_sub()
test_mul()
test_sandwich()


def test_eq():
alias g3 = Signature(3, 0, 0)
assert_true(Multivector[g3, g3.empty_mask()]().__eq__(Float64(0)))
assert_true(Multivector[g3, g3.vector_mask()](1, 2, 3).__eq__(Multivector[g3, g3.vector_mask()](1, 2, 3)))
assert_false(Multivector[g3, g3.vector_mask()](1, 2, 3).__eq__(Multivector[g3, g3.vector_mask()](1, 4, 3)))
assert_false(Multivector[g3, g3.vector_mask()](1, 2, 3).__eq__(Float64(1)))


def test_ne():
alias g3 = Signature(3, 0, 0)
assert_false(Multivector[g3, g3.empty_mask()]().__ne__(Float64(0)))
assert_false(Multivector[g3, g3.vector_mask()](1, 2, 3).__ne__(Multivector[g3, g3.vector_mask()](1, 2, 3)))
assert_true(Multivector[g3, g3.vector_mask()](1, 2, 3).__ne__(Multivector[g3, g3.vector_mask()](1, 4, 3)))
assert_true(Multivector[g3, g3.vector_mask()](1, 2, 3).__ne__(Float64(1)))


def test_subspace_constructor():
assert_true(scalar[G3](6) == Multivector[G3](6))
assert_true(scalar[G3](0) != Multivector[G3](6))

assert_true(vector[G3](1, 2, 3) == Multivector[G3, G3.vector_mask()](1, 2, 3))
assert_true(vector[G3](1, 0, 3) != Multivector[G3, G3.vector_mask()](1, 2, 3))

assert_true(bivector[G3](4, 5, 6) == Multivector[G3, G3.bivector_mask()](4, 5, 6))
assert_true(bivector[G3](4, 0, 6) != Multivector[G3, G3.bivector_mask()](4, 5, 6))


def test_getattr():
alias g3 = Signature(3, 0, 0)
alias scalar_vector_mask = List(True, True, True, True, False, False, False, False)
assert_equal(Multivector[g3](6).s, Float64(6))
assert_equal(Multivector[g3, g3.vector_mask()](7, 8, 9).s, Float64(0))
assert_equal(Multivector[g3, scalar_vector_mask](6, 7, 8, 9).s, Float64(6))


def test_normalized():
alias g3 = Signature(3, 0, 0)
assert_true(Multivector[g3, g3.vector_mask()](1, 2, 3).normalized() == Multivector[g3, g3.vector_mask()](0.2672612419124244, 0.53452248382484879, 0.80178372573727319))
assert_true(Multivector[g3, g3.bivector_mask()](1, 2, 3).normalized() == Multivector[g3, g3.bivector_mask()](0.2672612419124244, 0.53452248382484879, 0.80178372573727319))


def test_add():
alias g3 = Signature(3, 0, 0)
alias scalar_vector_mask = List(True, True, True, True, False, False, False, False)
assert_true(Multivector[g3, g3.vector_mask()](1, 2, 3).__add__(Multivector[g3, g3.vector_mask()](1, 2, 3)) == Multivector[g3, g3.vector_mask()](2, 4, 6))
assert_true(Multivector[g3, g3.vector_mask()](1, 2, 3).__add__(Float64(1)) == Multivector[g3, scalar_vector_mask](1, 1, 2, 3))


def test_sub():
alias g3 = Signature(3, 0, 0)
alias scalar_vector_mask = List(True, True, True, True, False, False, False, False)
assert_true(Multivector[g3, g3.vector_mask()](2, 4, 6).__sub__(Multivector[g3, g3.vector_mask()](1, 2, 3)) == Multivector[g3, g3.vector_mask()](1, 2, 3))
assert_true(Multivector[g3, g3.vector_mask()](1, 2, 3).__sub__(Float64(1)) == Multivector[g3, scalar_vector_mask](-1, 1, 2, 3))


def test_mul():
alias g3 = Signature(3, 0, 0)
assert_true(Multivector[g3, g3.vector_mask()](1, 2, 3).__mul__(Float64(2)) == Multivector[g3, g3.vector_mask()](2, 4, 6))
assert_true(Multivector[g3, g3.vector_mask()](1, 2, 3).__mul__(Multivector[g3, g3.antiscalar_mask()](1)) == Multivector[g3, g3.bivector_mask()](3, -2, 1))

alias ug3 = Signature(1, 1, 1, flip_ze = False)
alias v1_mask = List(False, True, False, False, False, False, False, False)
assert_true(Multivector[ug3, v1_mask](2).__mul__(Multivector[ug3, v1_mask](2)) == Float64(4))
alias v2_mask = List(False, False, True, False, False, False, False, False)
assert_true(Multivector[ug3, v2_mask](2).__mul__(Multivector[ug3, v2_mask](2)) == Float64(-4))
alias v3_mask = List(False, False, False, True, False, False, False, False)
assert_true(Multivector[ug3, v3_mask](2).__mul__(Multivector[ug3, v3_mask](2)) == Float64(0))

alias pg3 = Signature(3, 0, 1, flip_ze = True)
alias niltrivector_mask = List(False, False, False, False, False, False, False, False, False, False, False, True, True, True, False, False)
assert_true(Multivector[pg3, pg3.vector_mask()](1, 2, 3, 4).__mul__(Float64(2)) == Multivector[pg3, pg3.vector_mask()](2, 4, 6, 8))
assert_true(Multivector[pg3, pg3.vector_mask()](1, 2, 3, 4).__mul__(Multivector[pg3, pg3.antiscalar_mask()](1)) == Multivector[pg3, niltrivector_mask](-4, 3, -2))


def test_sandwich():
alias g3 = Signature(3, 0, 0)
assert_true(Multivector[g3, g3.even_mask()](0, 1, 0, 0)(Multivector[g3, g3.vector_mask()](1, 2, 3)) == Multivector[g3, g3.vector_mask()](-1, -2, 3))

0 comments on commit cf19a83

Please sign in to comment.