Galixir.Algebras.CGA2 (galixir v0.34.0)

Copy Markdown View Source

Two-dimensional Conformal Geometric Algebra (CGA).

This module implements CGA for the Euclidean plane using the metric:

`{1, 1, 1, -1}`

with basis vectors:

`e1, e2, ep, em`

where ep and em are the positive and negative basis vectors used to construct the null vectors e_inf and e_o.

The conformal basis is defined as:

`e_inf = e_m + e_p`
`e_o = (e_m - e_p) / 2`

Points are embedded using the standard conformal embedding:

`P(x,y) = e_o + x*e1 + y*e2 + 1/2(x²+y²)e_inf`

Objects are represented as multivectors and can be combined using the operations provided by Galixir.GeometricAlgebra.

The implementation uses the pseudoscalar to convert between OPNS and IPNS representations.

Examples

iex> p = Galixir.Algebras.CGA2.point(2, 3)
iex> Galixir.Algebras.CGA2.point_coordinates(p)
{2.0, 3.0}

Summary

Functions

Adds two multivectors component-wise.

This function checks that the object has bivector grade and contains finite point-pair structure. Use split/1 to extract the actual points.

Checks whether a multivector is a blade.

Returns the number of coefficients stored by the algebra.

Returns the mapping between blade names and storage indices.

Returns the canonical sign of a multivector.

Creates a circle from a center point and radius.

Creates a circle from Euclidean coordinates and radius.

Returns whether a multivector represents an OPNS circle.

Returns whether a multivector is an OPNS circle or line.

Extracts the Euclidean parameters of an OPNS circle or line.

Classifies a geometric object and extracts its Euclidean parameters.

Removes coefficients whose absolute value is below eps.

Returns the coefficient of a basis blade.

Computes the commutator product of two multivectors.

Tests whether a point lies on a conformal object.

Returns the dimension of the algebra.

Returns the pseudoscalar dual of a multivector.

Returns the conformal infinity vector.

Returns the conformal origin vector.

Formats this multivector as geometric algebra notation.

Computes the geometric product of two multivectors.

Returns the grade of a homogeneous multivector.

Extracts the grade-g component of a multivector.

Checks whether a multivector contains components of the given grade only.

Returns the grades present in a multivector.

Computes the Hodge dual of a multivector.

Computes the inverse Hodge dual of a multivector.

Computes the inner product of two multivectors.

Computes the inverse of a multivector.

Computes the inverse of a multivector.

A guard that checks if a floating point number is below the epsilon threshold.

Checks whether a multivector contains components of the given grade only.

A guard that matches multi vectors that are all zero.

Computes the outer product join of two CGA objects.

Computes the left contraction of two multivectors.

Lifts an affine point representative back into the conformal point embedding.

Creates a conformal line through two points.

Returns whether a multivector is an OPNS line.

Creates an OPNS circle or degenerate line through three conformal points.

Returns the Euclidean coefficients of an OPNS line.

Returns the maximum absolute coefficient of a multivector.

Computes the meet (incidence) operation between two objects.

Returns the metric of the algebra.

Returns the norm of a multivector.

Normalizes a multivector.

Normalizes a conformal point so that its conformal weight is -1.

Returns the scalar identity element.

Parses a string representation into a multivector.

Embeds a Euclidean point into conformal space.

Returns whether a multivector is a finite conformal point.

Extracts Euclidean coordinates from a conformal point.

Returns the pseudoscalar

Applies the reverse operation to a multivector.

Computes the right contraction of two multivectors.

Creates a Euclidean rotation rotor.

Computes the rotor that maps one frame to another.

Turns a Multivector with only a scalar part into an elixir number.

Checks whether a multivector contains only a scalar component.

Returns the scalar coefficient of a multivector.

Computes the scalar product of two multivectors.

Creates a multivector from a string representation.

Splits a point pair into its two conformal points.

Returns the squared norm of a multivector.

Subtracts two multivectors component-wise.

Returns the multiplication table for the algebra.

Turns a Multivector with only a scalar part into an elixir number.

Applies a motor transformation to a CGA object.

Creates a translator motor for translating by (x, y).

Returns the inverse pseudoscalar dual of a multivector.

Creates a Euclidean vector embedded in CGA.

Computes the outer product (wedge product) of two multivectors.

Computes the outer product of a list of multivectors.

Returns the zero multivector.

Checks whether all coefficients of a multivector are zero.

Functions

above_epsilon?(num, eps \\ 1.0e-10)

add(arg1, arg2)

Adds two multivectors component-wise.

Examples

iex> a = new(scalar: 2)
iex> b = new(scalar: 3)
iex> add(a, b)
new(scalar: 5)

basis_name(int)

bivector_candidate?(x)

This function checks that the object has bivector grade and contains finite point-pair structure. Use split/1 to extract the actual points.

This function only checks the grade. Use split/1 to determine whether the bivector represents a valid point pair.

Examples

iex> pp = meet(
...>   circle(point(0, 0), 2),
...>   line(point(-2, 0), point(2, 0))
...> )
iex> bivector_candidate?(pp)
true

blade?(a)

Checks whether a multivector is a blade.

A blade is a multivector containing components from at most one grade.

Scalars are considered blades.

Examples

iex> blade?(new(e1: 2))
true

iex> blade?(new(e12: 1))
true

iex> blade?(new(e1: 1, e2: 1))
true

iex> blade?(new(scalar: 2, e1: 2))
false

iex> blade?(new(e2: 2, e12: 2))
false

blade_count()

Returns the number of coefficients stored by the algebra.

A dimension n algebra contains 2^n basis blades.

blade_indices()

Returns the mapping between blade names and storage indices.

Blade coefficients are stored in a fixed-blade_count tuple. This map translates canonical blade names into their corresponding tuple index.

Example

iex> blade_indices()[:e1]
1

blade_inverse(b)

canonical_sign(cga2)

Returns the canonical sign of a multivector.

The canonical sign is determined by the first non-zero coefficient in storage order.

Returns:

  • 1 if the first non-zero coefficient is positive
  • -1 if the first non-zero coefficient is negative
  • 0 if all coefficients are zero

Examples

iex> canonical_sign(new(e1: 2))
1

iex> canonical_sign(new(e1: -2))
-1

iex> canonical_sign(new())
0

canonical_sign_tuple(arg)

canonicalize(a)

canonicalize!(a)

circle(p, r)

Creates a circle from a center point and radius.

The returned multivector represents the conformal circle object.

Examples

iex> circle(1, 2, 3)
~G"1.5e12p + 2.5e12m + 2.0e1pm - e2pm"

iex> circle?(circle(1, 2, 3))
true

iex> circle_parameters(circle(1, 2, 3))
{:circle, {:real, {1.0, 2.0}, 3.0}}

iex> circle_parameters(circle(1, 2, -3))
{:circle, {:imag, {1.0, 2.0}, 3.0}}

iex> c = circle(point(1, 2), 3)
iex> contains?(c, point(4, 2))
true
iex> contains?(c, point(5, 2))
false

circle(x, y, r)

Creates a circle from Euclidean coordinates and radius.

circle?(x)

Returns whether a multivector represents an OPNS circle.

Lines are also grade-3 blades in CGA2, so they are excluded.

Examples

iex> circle?(circle(point(0, 0), 2))
true

iex> circle?(line(point(0, 0), point(1, 0)))
false

circle_or_line?(c)

Returns whether a multivector is an OPNS circle or line.

In CGA2 both circles and lines are grade-3 objects. Lines are exactly those trivectors containing e_inf.

Use line?/1 to distinguish lines.

Examples

iex> circle_or_line?(circle(point(0, 0), 2))
true

circle_parameters(c)

Extracts the Euclidean parameters of an OPNS circle or line.

Returns either

  • {:circle, {{x, y}, radius}}
  • {:line, {a, b, c}}

where the line satisfies ax + by + c = 0.

Examples

iex> circle_parameters(circle(point(1, 2), 3))
{:circle, {:real, {1.0, 2.0}, 3.0}}

iex> circle_parameters(circle(point(1, 2), -3.0))
{:circle, {:imag, {1.0, 2.0}, 3.0}}

classify(x)

Classifies a geometric object and extracts its Euclidean parameters.

Returns one of

  • {:point, {x, y}}
  • {:line, {a, b, c}}
  • {:circle, {{x, y}, radius}}
  • {:point_pair, p1, p2}
  • {:point_pair, p}
  • {:unknown, multivector}

Examples

iex> classify(point(2, 3))
{:point, {2.0, 3.0}}

iex> classify(point(-5, 4))
{:point, {-5.0, 4.0}}

iex> {:line, {a, b, c}} = classify(line(point(0, 0), point(0, 1)))
iex> abs(a) == 1.0 and b == 0.0 and c == 0.0
true

iex> {:line, {a, b, c}} = classify(line(point(0, 0), point(1, 0)))
iex> a == 0.0 and abs(b) == 1.0 and c == 0.0
true

iex> classify(circle(point(0, 0), 2))
{:circle, {:real, {0.0, 0.0}, 2.0}}

iex> classify(circle(point(3, -2), 5))
{:circle, {:real, {3.0, -2.0}, 5.0}}

iex> pp =
...>   meet(
...>     circle(point(0, 0), 2),
...>     line(point(-3, 0), point(3, 0))
...>   )
iex> {:point_pair, p1, p2} = classify(pp)
iex> Enum.sort([p1, p2])
[{-2.0, 0.0}, {2.0, 0.0}]

iex> pp =
...>   meet(
...>     circle(point(0, 0), 1),
...>     line(point(-2, 0), point(2, 0))
...>   )
iex> match?({:point_pair, _, _}, classify(pp))
true

iex> pp =
...>   meet(
...>     circle(point(1, 2), 1),
...>     circle(point(3, 2), 1)
...>   )
iex> classify(pp)
{:point_pair, {2.0, 2.0}}

iex> pp =
...>   meet(
...>     circle(point(1, -1), 1),
...>     circle(point(1, -3), 1)
...>   )
iex> classify(pp)
{:point_pair, {1.0, -2.0}}

iex> classify(meet(circle(point(0,0),1), circle(point(0,0),1)))
{:unknown, ~G[0.0]}

iex> classify(new(e1: 1))
{:unknown, new(e1: 1)}

iex> {:point_pair, _, _} =  classify(join(point(0,0), point(1,0)))

cleanup(m, eps \\ epsilon())

Removes coefficients whose absolute value is below eps.

This is useful for cleaning up floating-point round-off errors after geometric computations.

Examples

iex> new(e1: 1.0, e2: 1.0e-12)
...> |> cleanup()
...> |> coefficient(:e2)
0.0

coefficient(cga2, blade)

Returns the coefficient of a basis blade.

The requested blade can be given in canonical form or as any registered blade alias. Aliases are automatically converted to the canonical blade and the appropriate sign is applied.

Examples

iex> coefficient(
...>  new(e1: 3),
...>  :e1
...> )
3.0

commutator(a, b)

Computes the commutator product of two multivectors.

The commutator is defined as half the difference between the geometric products in opposite orders:

[a, b] = (a * b - b * a) / 2

This measures the non-commutativity of the geometric product.

Examples

iex> commutator(new(e1: 1), new(e2: 1))
new(e12: 1)

iex> commutator(new(e2: 1), new(e1: 1))
new(e12: -1)

iex> commutator(new(e1: 1), new(e1: 1))
new()

iex> commutator(new(e1: 1), new(scalar: 2))
new()

contains?(object, point)

Tests whether a point lies on a conformal object.

Returns true when the incidence meet operation produces the zero multivector.

Examples

iex> l = line(point(0,0), point(1,0))
iex> contains?(l, point(2,0))
true
iex> contains?(l, point(0,1))
false

degenerate?()

dimension()

Returns the dimension of the algebra.

This is the number of basis vectors defined by the metric.

dual(mv)

Returns the pseudoscalar dual of a multivector.

The dual is computed by multiplying the multivector by the inverse of the algebra's pseudoscalar.

This operation is only defined for non-degenerate algebras, where the pseudoscalar is invertible.

See hodge_dual/1 and hodge_undual/1 for the metric-independent Hodge dual.

Examples

iex> p = new(scalar: 2.0)
iex> undual(dual(p)) == p
true

iex> p = new(scalar: 2.0)
iex> dual(undual(p)) == p
true

e_inf()

Returns the conformal infinity vector.

The infinity vector represents the point at infinity in conformal space:

`e_inf = e_m + e_p`

Examples

iex> scalar_product(e_inf(), e_inf())
0.0

e_o()

Returns the conformal origin vector.

The origin is defined as:

`e_o = (e_m - e_p) / 2`

Examples

iex> scalar_product(e_o(), e_inf())
-1.0

epsilon()

format(value, opts)

Formats this multivector as geometric algebra notation.

This is the same representation used by Inspect.

Examples

iex> inspect(new())
"~G[0.0]"

iex> inspect(new(), custom_options: [all_blades: true])
"~G[0.0 + 0.0e1 + 0.0e2 + 0.0e12 + 0.0ep + 0.0e1p + 0.0e2p + 0.0e12p + 0.0em + 0.0e1m + 0.0e2m + 0.0e12m + 0.0epm + 0.0e1pm + 0.0e2pm + 0.0e12pm]"

iex> inspect(new(scalar: -2))
"~G[-2.0]"

iex> inspect(new(scalar: 2))
"~G[2.0]"

iex> inspect(new(scalar: -2))
"~G[-2.0]"

iex> inspect(new(e1: 1))
"~G[1.0e1]"

iex> inspect(new(scalar: 1, e1: 2))
"~G[1.0 + 2.0e1]"

iex> inspect(new(scalar: 1, e1: -2))
"~G[1.0 - 2.0e1]"

iex> inspect(new(scalar: -1, e1: -2))
"~G[-1.0 - 2.0e1]"

iex> inspect(new(scalar: -1, e1: 2))
"~G[-1.0 + 2.0e1]"

iex> inspect(new(e1: 2))
"~G[2.0e1]"

iex> inspect(new(e1: -2))
"~G[-2.0e1]"

iex> inspect(~G[ε + εe1])
"~G[ε + εe1]"
iex> inspect(~G[-ε - εe1])
"~G[-ε - εe1]"

gp(cga21, cga22)

Computes the geometric product of two multivectors.

The geometric product is the fundamental multiplication operation of geometric algebra. It combines the outer product and metric-dependent inner product into a single associative operation.

The result depends on the algebra's metric.

Examples

iex> gp(
...>   new(e1: 1),
...>   new(e1: 1)
...> )
new(scalar: 1)

grade(x)

Returns the grade of a homogeneous multivector.

The zero multivector is considered grade 0.

Returns nil for mixed-grade multivectors.

Examples

iex> grade(
...>   new(scalar: 1)
...> )
0

iex> grade(
...>   new(e1: 2)
...> )
1

iex> grade(
...>   new(scalar: 1, e1: 2)
...> )
nil

iex> grade(
...>   new()
...> )
nil

grade(t, g)

Extracts the grade-g component of a multivector.

All coefficients whose basis blades are not of grade g are set to zero.

Raises ArgumentError if g is outside the range 0..dimension().

Examples

iex> grade(
...>   new(scalar: 1, e1: 2),
...>   1
...> )
new(e1: 2)

iex> grade(
...>   new(scalar: 1, e1: 2),
...>   0
...> )
new(scalar: 1)

grade?(mv, g)

Checks whether a multivector contains components of the given grade only.

A multivector is considered to have a grade if all non-zero components belong to that grade. The zero multivector is considered to have grade 0.

Examples

iex> grade?(new(e1: 1), 1)
true

iex> grade?(new(scalar: 1, e1: 2), 2)
false

iex> grade?(new(scalar: 1), 0)
true

iex> grade?(new(), 0)
true

See is_grade/2

grades(arg1)

Returns the grades present in a multivector.

The returned list contains every grade with at least one non-zero coefficient, ordered from lowest to highest.

Examples

iex> grades(
...>   new(scalar: 1)
...> )
[0]

iex> grades(
...>   new(e1: 2)
...> )
[1]

iex> grades(
...>   new(scalar: 1, e1: 2)
...> )
[0, 1]

iex> grades(
...>   new()
...> )
[]

hodge_dual(cga2)

Computes the Hodge dual of a multivector.

The Hodge dual maps each basis blade to its complementary blade with the appropriate orientation sign. The complementary blade is determined by the pseudoscalar of the algebra.

The operation is linear and is applied independently to each basis blade and its coefficient.

Unlike the pseudoscalar dual, the Hodge dual does not require the pseudoscalar to be invertible and is therefore also defined for degenerate algebras.

The operations are inverses:

hodge_undual(hodge_dual(a)) == a
hodge_dual(hodge_undual(a)) == a

See hodge_undual/1 for the inverse operation. See dual/1 for the pseudoscalar-based dual.

Examples

iex> hodge_dual(new(e1: 1)) |> inspect
new(e2pm: 1.0) |> inspect

hodge_undual(cga2)

Computes the inverse Hodge dual of a multivector.

hodge_undual/1 reverses the blade-complement operation performed by hodge_dual/1, mapping each basis blade back to its complementary blade with the appropriate orientation sign.

The operation is linear and is applied independently to each basis blade and its coefficient.

Unlike the pseudoscalar dual, the Hodge dual and its inverse are defined for degenerate algebras as well.

The operations are inverses:

hodge_undual(hodge_dual(a)) == a
hodge_dual(hodge_undual(a)) == a

See hodge_dual/1 for the inverse operation. See dual/1 for the pseudoscalar-based dual.

Examples

iex> hodge_undual(hodge_dual(new(e1: 2)))
new(e1: 2)

inner(arg1, arg2)

Computes the inner product of two multivectors.

The operation is generated from the geometric product and retains only terms satisfying the grade selection rule.

Example

iex> inner(
...>   new(e1: 2),
...>   new(e1: 3)
...> )

inverse(a)

Computes the inverse of a multivector.

The inverse is computed using the reverse:

inverse(a) = reverse(a) / scalar_part(a * reverse(a))

This formula is valid when a * reverse(a) is a non-zero scalar.

Returns either {:ok, result} if inverse can be compute or :error otherwise

Examples

iex> inverse(
...>   new(e1: 2)
...> )
{:ok, new(e1: 0.5) }

iex> inverse(
...>   new(e1: 2)
...> )
{:ok, new(e1: 0.5)}

iex> inverse(
...>   new(scalar: 0.0)
...> )
:error

inverse!(a)

Computes the inverse of a multivector.

The inverse is computed using the reverse:

inverse!(a) = reverse(a) / scalar_part(a * reverse(a))

This formula is valid when a * reverse(a) is a non-zero scalar.

Raises ArgumentError if the multivector is not invertible by this formula.

Examples

iex> inverse!(
...>   new(e1: 2)
...> )
new(e1: 0.5)

iex> inverse!(
...>   new(e1: 2)
...> )
new(e1: 0.5)

iex> assert_raise ArgumentError, fn ->
...>   inverse!(new(scalar: 0))
...> end

is_above_epsilon(num, eps \\ 1.0e-10)

(macro)

A guard that checks if a floating point number is below the epsilon threshold.

Can be used in function guards:

def foo(x) when is_near_zero(x), do: x

is_blade(mv)

(macro)

is_grade(mv, grade)

(macro)

Checks whether a multivector contains components of the given grade only.

A multivector is considered to have a grade if all non-zero components belong to that grade. The zero multivector is considered to have grade 0.

The is_grade(vector, grade) guard can be used in function guards:

def foo(mv) when is_grade(mv, 1) do
  mv
end

Examples

iex> grade?(new(e1: 1), 1)
true

iex> grade?(new(scalar: 1, e1: 2), 2)
false

iex> grade?(new(scalar: 1), 0)
true

iex> grade?(new(), 0)
true

See grade?/2

is_zero(mv)

(macro)

A guard that matches multi vectors that are all zero.

Can be used in function guards:

def foo(x) when is_zero(x), do: x

join(a, b)

Computes the outer product join of two CGA objects.

The join is the wedge product:

join(a, b) = a ∧ b

This operates on the actual multivector representations. Objects represented in IPNS form should be converted to OPNS form before using the join.

For OPNS objects, the result is the smallest blade containing both.

Examples

iex> l =
...>   join(
...>     point(0, 0),
...>     point(1, 0)
...>   )
iex> grades(l)
[2]

iex> c =
...>   join(
...>     join(
...>       point(1, 0),
...>       point(0, 1)
...>     ),
...>     point(-1, 0)
...>   )
iex> grades(c)
[3]

iex> c =
...>   join(
...>     point(1,0),
...>     point(0,1),
...>     point(-1,0)
...>   )
iex> circle_parameters(c)
{:circle, {:real, {0.0, 0.0}, 1.0}}

join(a, b, c)

left_contraction(arg1, arg2)

Computes the left contraction of two multivectors.

The operation is generated from the geometric product and retains only terms satisfying the grade selection rule.

Example

iex> left_contraction(
...>   new(e1: 2),
...>   new(e1: 3)
...> )

lift_point(p)

Lifts an affine point representative back into the conformal point embedding.

Examples

iex> lift_point(point(2, 3))
...> |> point_coordinates()
{2.0, 3.0}

iex> lift_point(point(2,3))
add(add(e_o(), add(new(e1: 2), new(e2: 3))), scale(6.5, e_inf()))

iex> point_coordinates(lift_point(point(4,5)))
{4.0,5.0}

iex> point?(lift_point(point(1,2)))
true

line(a, b)

Creates a conformal line through two points.

The line is represented using the outer product:

`L = a  b  e_inf`

Examples

iex> line?(line(point(0,0), point(1,0)))
true

iex> contains?(line(point(0,0), point(1,0)), point(0.5,0))
true

iex> l = line(point(0, 0), point(1, 0))
iex> line?(l)
true

iex> contains?(line(point(0, 0), point(1, 0)), point(2, 0))
true

iex> contains?(line(point(0, 0), point(1, 0)), point(0, 1))
false

iex> l = line(point(2, -1), point(2, 3))
iex> contains?(l, point(2, 10))
true
iex> contains?(l, point(3, 0))
false

line?(l)

Returns whether a multivector is an OPNS line.

Examples

iex> line?(line(point(0, 0), point(1, 0)))
true

iex> line?(circle(point(0, 0), 1))
false

line_or_circle_from_points(a, b, c)

Creates an OPNS circle or degenerate line through three conformal points.

The circle is represented by the outer product:

`C = a  b  c`

For collinear points this degenerates to a line.

Examples

iex> c =
...>   line_or_circle_from_points(
...>     point(1, 0),
...>     point(0, 1),
...>     point(-1, 0)
...>   )
iex> circle?(c)
true
iex> circle_parameters(c)
{:circle, {:real, {0.0, 0.0}, 1.0}}

iex> c =
...>   line_or_circle_from_points(
...>     point(0, 0),
...>     point(1, 0),
...>     point(0, 1)
...>   )
iex> contains?(c, point(0, 0))
true

iex> c =
...>   line_or_circle_from_points(
...>     point(0, 0),
...>     point(1, 0),
...>     point(2, 0)
...>   )
iex> line?(c)
true

line_parameters(l)

Returns the Euclidean coefficients of an OPNS line.

The returned tuple {a, b, c} satisfies

`ax + by + c = 0`

Examples

iex> {a, b, c} = line_parameters(line(point(0, 0), point(0, 1)))
iex> {abs(a), b, c}
{1.0, 0.0, 0.0}

iex> line_parameters(line(point(0, 0), point(1, 2)))
{-2.0, 1.0, 0.0}

iex> line_parameters(line(point(0,0), point(1,0)))
{0.0, 1.0, 0.0}

max_abs_component(cga2)

Returns the maximum absolute coefficient of a multivector.

Accepts either a multivector struct or the internal coefficient tuple.

Example

iex> max_abs_component(new(e1: 2, scalar: 5))
5.0

iex> max_abs_component(new(e1: 5, scalar: 2))
5.0

max_abs_component_tuple(arg)

meet(a, b)

Computes the meet (incidence) operation between two objects.

The meet is implemented using duality:

meet(a,b) = dual(dual(a) ∧ dual(b))

Examples

iex> l = line(point(-2,0), point(2,0))
iex> c = circle(point(0,0),1)
iex> bivector_candidate?(meet(c,l))
true

iex> c1 = circle(point(1, 2), 1)
iex> c2 = circle(point(3, 2), 1)
iex> {:tangent, p} = split(meet(c1, c2) )
iex> p |> point_coordinates()
{2.0, 2.0}

iex> c1 = circle(point(1, -1), 1)
iex> c2 = circle(point(1, -3), 1)
iex> {:tangent, p} = split(meet(c1, c2))
iex> p |> point_coordinates()
{1.0, -2.0}

iex> pp =
...>   meet(
...>     circle(point(0,0),1),
...>     circle(point(5,0),1)
...>   )
iex> match?({:point_pair, _, _}, classify(pp))
true

metric()

Returns the metric of the algebra.

Example:

{1, 1, 1, 0}

represents a projective geometric algebra with three Euclidean basis vectors and one null basis vector.

new(basis \\ [])

norm(a)

Returns the norm of a multivector.

The norm is the square root of the absolute squared norm.

Example

iex> a = new(scalar: 3)
iex> norm(a)
3.0

normalize(a)

normalize!(a)

Normalizes a multivector.

The result has unit norm while preserving the direction of the multivector.

Raises ArgumentError when attempting to normalize a null multivector.

Example

iex> a = new(scalar: 2)
iex> norm(normalize!(a))
1.0

iex> normalize!(new())
** (ArgumentError) cannot normalize given null multivector ...

iex> normalize!(new(scalar: epsilon() / 2.0))
** (ArgumentError) cannot normalize given null multivector ...

normalize_point(p)

Normalizes a conformal point so that its conformal weight is -1.

The weight is defined as:

w = p · e_o

and this module uses the convention that normalized points satisfy:

p · e_o = -1

Raises ArgumentError if the point has zero weight.

Examples

iex> p = point(2, 3) |> scale(5)
iex> normalized = normalize_point(p)
iex> scalar_product(normalized, e_o())
-1.0

iex> {x, y} = normalize_point(scale(point(8, 2), 100)) |> point_coordinates()
iex> abs(x - 8.0) < 1.0e-10 and abs(y - 2.0) < 1.0e-10
true

one()

Returns the scalar identity element.

This is the multiplicative identity.

Examples

iex> one()
~G"1.0"

parse(string)

Parses a string representation into a multivector.

The string may contain scalar coefficients and basis blades combined using + and - operators.

Examples:

iex> parse("1 + e1")
new(scalar: 1, e1: 1)

iex> parse("foo")
** (ArgumentError) expected number ...

point(x, y)

Embeds a Euclidean point into conformal space.

Uses the standard CGA point representation:

`P = e_o + x * e1 + y * e2 + 1/2*(x²+y²)*e_inf`

Examples

iex> point_coordinates(point(1, 2))
{1.0, 2.0}

point?(p)

Returns whether a multivector is a finite conformal point.

A finite point is a grade-1 null vector with non-zero weight.

Examples

iex> point?(point(1, 2))
true

iex> point?(new(e1: 1, e2: 1))
false

point_coordinates(p)

Extracts Euclidean coordinates from a conformal point.

Returns a tuple:

`{x, y}`

Examples

iex> point(2, 3)
...> |> scale(7)
...> |> point_coordinates()
{2.0, 3.0}

pseudoscalar()

Returns the pseudoscalar:

e1 ∧ e2 ∧ ep ∧ em

iex> grades(pseudoscalar())
[4]

reverse(cga2)

Applies the reverse operation to a multivector.

Reverse (also called reversion) changes the sign of basis blades according to their grade:

grade 0:  +
grade 1:  +
grade 2:  -
grade 3:  -
grade 4:  +
...

For a blade with grade r, the sign is:

(-1)^(r(r-1)/2)

Examples

iex> reverse(new(e1: 2))
new(e1: 2)

iex> reverse(new(e12: 2))
new(e12: -2)

iex> reverse(new(scalar: 3))
new(scalar: 3)

reverse_tuple(arg)

right_contraction(arg1, arg2)

Computes the right contraction of two multivectors.

The operation is generated from the geometric product and retains only terms satisfying the grade selection rule.

Example

iex> right_contraction(
...>   new(e1: 2),
...>   new(e1: 3)
...> )

rotor(angle)

Creates a Euclidean rotation rotor.

Rotates by angle radians around the origin.

The rotor is normalized before being returned.

Examples

iex> {x, y} = point(1, 0)
...> |> transform(rotor(:math.pi() / 2))
...> |> cleanup()
...> |> point_coordinates()
iex> abs(x) < 1.0e-10
true
iex> abs(y - 1.0) < 1.0e-10
true

rotor_between_frames(source, target)

Computes the rotor that maps one frame to another.

The function constructs blades from the source and target frames and computes the transformation rotor:

R = normalize(1 + T * S⁻¹)

where S is the source frame blade and T is the target frame blade.

The resulting rotor can be applied to multivectors to rotate the source frame into the target frame.

scalar(mv)

Turns a Multivector with only a scalar part into an elixir number.

iex> ~G[3.0] |> scalar()
{:ok, 3.0}

iex> ~G[3.0 + e1] |> scalar()
:error

scalar?(cga2)

Checks whether a multivector contains only a scalar component.

Components with an absolute value smaller than eps are considered zero.

Examples

iex> scalar?(new(scalar: 3))
true

iex> scalar?(new(e1: 3))
false

iex> scalar?(new())
true

scalar?(arg, eps \\ 1.0e-12)

scalar_part(cga2)

Returns the scalar coefficient of a multivector.

This is equivalent to retrieving the coefficient of the scalar blade.

Examples

iex> scalar_part(new(scalar: 5.0, e1: 2.0))
5.0

scalar_product(a, b)

Computes the scalar product of two multivectors.

This is the scalar part of the geometric product. It uses the CGA metric defined by the module metric options.

Examples

iex> scalar_product(new(e1: 1), new(e1: 1))
1.0

iex> scalar_product(point(1,0), new(e1: 1))
1.0

scale(s, s)

sigil_G(arg, list)

(macro)

Creates a multivector from a string representation.

The ~G sigil provides a convenient syntax for constructing multivectors using basis blades and coefficients.

Examples:

iex> ~G"e1 + e2"
new(e1: 1, e2: 1)

iex> ~G"2e1 - 0.5e12"
new(e1: 2, e12: -0.5)

iex> ~G"e12"
new(e12: 1)

iex> ~G"3"
new(scalar: 3)

iex> ~G[ε + εe1]
new(scalar: epsilon(), e1: epsilon())

iex> ~G[-ε - εe1]
new(scalar: -epsilon(), e1: -epsilon())

The parsed expression is converted into the same representation accepted by new/1, so blade ordering and signs are handled by the algebra implementation.

split(b)

Splits a point pair into its two conformal points.

Returns

  • {p1, p2} for two points,
  • :error if the bivector is not a valid point pair.

Examples

iex> l = line(point(-2, 0), point(2, 0))
iex> c = circle(point(0, 0), 1)
iex> {p1, p2} = split(meet(c, l))
iex> Enum.sort([point_coordinates(p1), point_coordinates(p2)])
[{-1.0, 0.0}, {1.0, 0.0}]

iex> c1 = circle(point(-0.5, 0), 1)
iex> c2 = circle(point(0.5, 0), 1)
iex> {p1, p2} = split(meet(c1, c2))
iex> [{x1, y1}, {x2, y2}] = Enum.sort([point_coordinates(p1), point_coordinates(p2)])
iex> abs(x1) < 1.0e-10 and abs(x2) < 1.0e-10
true
iex> (y1 < 0) != (y2 < 0)
true
iex> abs(abs(y1) - 0.75 ** 0.5) < 1.0e-10
true
iex> abs(abs(y2) - 0.75 ** 0.5) < 1.0e-10
true

iex> split(meet(circle(point(0,0),1), circle(point(0,0),1)))
:error

iex> c1 = circle(point(0,0),1)
iex> c2 = circle(point(5,0),1)
iex> {_, _} = split(meet(c1,c2))

iex> l = line(point(-1,1), point(1,1))
iex> c = circle(point(0,0),1)
iex> {:tangent, p} = split(meet(c,l))
iex> point_coordinates(p)
{0.0,1.0}

iex> pp = join(point(0.0,0.0), point(1,0))
iex> {a, b} = split(pp)
iex> point_coordinates(a)
{1.0, 0.0}
iex> point_coordinates(b)
{0.0, 0.0}

squared_norm(a)

Returns the squared norm of a multivector.

The squared norm is computed as:

scalar_part(a * reverse(a))

The result may be negative for algebras with indefinite metrics.

This is also called the Spinor Magnitude.

Example

iex> a = new(scalar: 3)
iex> squared_norm(a)
9.0

sub(arg1, arg2)

Subtracts two multivectors component-wise.

Examples

iex> a = new(scalar: 5)
iex> b = new(scalar: 2)
iex> sub(a, b)
new(scalar: 3)

table()

Returns the multiplication table for the algebra.

The table contains precomputed geometric products between basis blades. Each entry maps {left_blade, right_blade} to {coefficient, result_blade}.

The blades are represented internally as bitmasks.

Example

iex> table() |> Map.has_key?({1, 1})
true

to_scalar(mv)

Turns a Multivector with only a scalar part into an elixir number.

Raises if the given Multivector is not grade 0.

iex> ~G[3.0] |> to_scalar()
3.0

iex> ~G[3.0 + e1] |> to_scalar()
** (ArgumentError) cannot convert multivector to scalar: only grade-0 multivectors can be converted to a scalar, got ...

transform(object, motor)

Applies a motor transformation to a CGA object.

Performs the sandwich product:

`M * X * reverse(M)`

Examples

iex> point(1, 2)
...> |> transform(translator(3, -1))
...> |> point_coordinates()
{4.0, 1.0}

translator(x, y)

Creates a translator motor for translating by (x, y).

The returned motor can be applied with transform/2.

Examples

iex> p = point(1, 2) |> transform(translator(3, -1))
iex> point_coordinates(p)
{4.0, 1.0}

undual(mv)

Returns the inverse pseudoscalar dual of a multivector.

This multiplies the multivector by the algebra's pseudoscalar and reverses the operation performed by dual/1.

See hodge_dual/1 and hodge_undual/1 for the metric-independent Hodge dual.

Examples

iex> p = new(scalar: 3.0)
iex> undual(dual(p)) == p
true

iex> p = new(scalar: 3.0)
iex> dual(undual(p)) == p
true

vector(x, y)

Creates a Euclidean vector embedded in CGA.

The vector is represented only by its Euclidean components:

`x * e1 + y * e2`

It is not a conformal point. Use point/2 to embed a point.

Examples

iex> point?(vector(1, 2))
false

iex> point?(point(1, 2))
true

wedge(arg1, arg2)

Computes the outer product (wedge product) of two multivectors.

The wedge product combines blades by joining their basis vectors. It is antisymmetric:

a  b = -(b  a)

and vanishes when the operands share a basis vector.

Examples

iex> wedge(
...>   new(e1: 1),
...>   new(e2: 1)
...> )
new(e12: 1)

iex> wedge(
...>   new(e2: 1),
...>   new(e1: 1)
...> )
new(e12: -1)

iex> wedge(
...>   new(e1: 1),
...>   new(e1: 1)
...> )
new()

wedge_all(vectors)

Computes the outer product of a list of multivectors.

The vectors are combined from left to right using the wedge product.

The result is a blade representing the subspace spanned by all input multivectors.

Examples

iex> wedge_all([])
new(scalar: 1)

iex> wedge_all([new(e1: 1)])
new(e1: 1)

iex> wedge_all([new(e1: 1), new(e1: 1)])
new()

iex> wedge_all([new(e1: 1), new(e2: 1)])
new(e12: 1)

iex> wedge_all([new(e2: 1), new(e1: 1)])
new(e12: -1)
iex> wedge_all([new(e1: 1), new(e2: 1), new(ep: 1)])
new(e12p: 1)

zero()

Returns the zero multivector.

Examples

iex> zero()
~G"0"

zero?(arg1)

Checks whether all coefficients of a multivector are zero.

Examples

iex> zero?(new())
true

iex> zero?(new(e1: 1))
false