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 13, 2024
1 parent 2013bac commit 72db45f
Show file tree
Hide file tree
Showing 5 changed files with 172 additions and 0 deletions.
38 changes: 38 additions & 0 deletions recipes/infrared/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Infrared
Infrared is a geometric algebra library for Mojo.

## Geometric Algebra
[Geometric algebras](https://en.wikipedia.org/wiki/Geometric_algebra) are [Clifford algebras](https://en.wikipedia.org/wiki/Clifford_algebra) 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 transformations such as lines, planes, rotations, etc.

Multivectors can be multiplied together using the 'geometric product'.

## Using Infrared
With infrared, you can generate the geometric product table for an arbitrary signature.

Multivectors are also parameterized on a basis masks, to avoid unnecessary overhead.

Example:
```mojo
alias sig = Signature(2, 0, 1)
var m = Multivector[sig, sig.vector_mask()](0.0, 1.0, 2.0)
print(m * m)
```

Infrared has no dependecies other than max.

Developers can use infrared as a mathematical abstraction over geometry (projective, conformal, spacetime, dimension-agnostic, etc.)

## Contributing
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.
41 changes: 41 additions & 0 deletions recipes/infrared/recipe.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
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
project_name: Infrared
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 72db45f

Please sign in to comment.