Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add recipe for infrared. #31

Merged
merged 9 commits into from
Jan 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.
44 changes: 44 additions & 0 deletions recipes/infrared/recipe.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
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=24.5
run:
- ${{ pin_compatible('max') }}

tests:
- script:
- if: unix
then:
- mojo run test.mojo
requirements:
run:
- max=24.5
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))
Loading