Skip to content

Commit

Permalink
Update the release notes (#403)
Browse files Browse the repository at this point in the history
This change:

* Adds documentation for the numba extension support
* Adds a summary of all the changes to multivector inverses
* Adds changelog entries for 1.4.0
* Pulls in two doc changes from #389
* Fixes weird indentation in the changelog page
* Updates the sphinx theme for good measure
  • Loading branch information
eric-wieser committed Jul 19, 2021
1 parent bfc4290 commit 659f75b
Show file tree
Hide file tree
Showing 10 changed files with 371 additions and 161 deletions.
49 changes: 42 additions & 7 deletions clifford/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
Constructing algebras
=====================
Note that typically the :doc:`predefined-algebras` are sufficient, and there is no need to build an algebra from scratch.
Note that typically the :doc:`/predefined-algebras` are sufficient, and there is no need to build an algebra from scratch.
.. autosummary::
:toctree:
Expand Down Expand Up @@ -77,7 +77,7 @@
import os
import itertools
import warnings
from typing import List, Tuple, Set
from typing import List, Tuple, Set, Dict

# Major library imports.
import numpy as np
Expand Down Expand Up @@ -318,11 +318,26 @@ def elements(dims: int, firstIdx=0) -> List[Tuple[int, ...]]:
return list(_powerset(range(firstIdx, firstIdx + dims)))


def Cl(p=0, q=0, r=0, sig=None, names=None, firstIdx=1, mvClass=MultiVector):
def Cl(p: int = 0, q: int = 0, r: int = 0, sig=None, names=None, firstIdx=1,
mvClass=MultiVector) -> Tuple[Layout, Dict[str, MultiVector]]:
r"""Returns a :class:`Layout` and basis blade :class:`MultiVector`\ s for the geometric algebra :math:`Cl_{p,q,r}`.
The notation :math:`Cl_{p,q,r}` means that the algebra is :math:`p+q+r`-dimensional, with the first :math:`p` vectors with positive signature, the next :math:`q` vectors negative, and the final :math:`r` vectors with null signature.
Parameters
----------
p : int
number of positive-signature basis vectors
q : int
number of negative-signature basis vectors
r : int
number of zero-signature basis vectors
sig
See the docs for :class:`clifford.Layout`. If ``sig`` is passed, then
`p`, `q`, and `r` are ignored.
names, firstIdx
See the docs for :class:`clifford.Layout`.
Returns
=======
layout : Layout
Expand All @@ -346,13 +361,33 @@ def basis_vectors(layout):


def randomMV(
layout, min=-2.0, max=2.0, grades=None, mvClass=MultiVector,
uniform=None, n=1, normed=False, rng=None):
layout: Layout, min=-2.0, max=2.0, grades=None, mvClass=MultiVector,
uniform=None, n=1, normed: bool = False, rng=None):
"""n Random MultiVectors with given layout.
Coefficients are between min and max, and if grades is a list of integers,
only those grades will be non-zero.
Parameters
------------
layout : Layout
the layout
min, max : Number
range of values from which to uniformly sample coefficients
grades : int, List[int]
grades which should have non-zero coefficients. If ``None``, defaults to
all grades. A single integer is treated as a list of one integers.
uniform : Callable[[Number, Number, Tuple[int, ...]], np.ndarray]
A function like `np.random.uniform`. Defaults to ``rng.uniform``.
n : int
The number of samples to generate. If ``n > 1``, this function
returns a list instead of a single multivector
normed : bool
If true, call :meth:`MultiVector.normal` on each multivector. Note
that this does not result in a uniform sampling of directions.
rng :
The random number state to use. Typical use would be to construct a
generator with :func:`numpy.random.default_rng`.
Examples
--------
Expand Down Expand Up @@ -387,7 +422,7 @@ def randomMV(
return mv


def conformalize(layout, added_sig=[1, -1], *, mvClass=MultiVector, **kwargs):
def conformalize(layout: Layout, added_sig=[1, -1], *, mvClass=MultiVector, **kwargs):
'''
Conformalize a Geometric Algebra
Expand All @@ -406,7 +441,7 @@ def conformalize(layout, added_sig=[1, -1], *, mvClass=MultiVector, **kwargs):
added_sig: list-like
list of +1, -1 denoted the added signatures
**kwargs :
passed to Cl() used to generate conformal layout
extra arguments to pass on into the :class:`Layout` constructor.
Returns
---------
Expand Down
8 changes: 2 additions & 6 deletions clifford/_layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -574,9 +574,7 @@ def comp_func(Xval):

@_cached_property
def _shirokov_inverse(self):
"""
Performs the inversion operation as described in Theorem 4, page 16 of the paper :cite:`shirokov2020inverse`
"""
""" See `MultiVector.shirokov_inverse` for documentation """
n = len(self.sig)
exponent = (n + 1) // 2
N = 2 ** exponent
Expand All @@ -594,9 +592,7 @@ def shirokov_inverse(U):

@_cached_property
def _hitzer_inverse(self):
"""
Performs the inversion operation as described in the paper :cite:`Hitzer_Sangwine_2017`
"""
""" See `MultiVector.hitzer_inverse` for documentation """
tot = len(self.sig)
@_numba_utils.njit
def hitzer_inverse(operand):
Expand Down
37 changes: 37 additions & 0 deletions clifford/_multivector.py
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,10 @@ def __call__(self, other, *others) -> 'MultiVector':
``M(N)`` calls :meth:`project` as ``N.project(M)``.
.. versionchanged:: 1.4.0
Grades larger than the dimension of the multivector now return 0
instead of erroring.
Examples
--------
>>> from clifford.g2 import *
Expand Down Expand Up @@ -738,9 +742,25 @@ def normal(self) -> 'MultiVector':
return self / abs(self)

def hitzer_inverse(self):
"""
Obtain the inverse :math:`M^{-1}` via the algorithm in the paper
:cite:`Hitzer_Sangwine_2017`.
.. versionadded:: 1.4.0
Raises
------
NotImplementedError :
on algebras with more than 5 non-null dimensions
"""
return self.layout._hitzer_inverse(self)

def shirokov_inverse(self):
"""Obtain the inverse :math:`M^{-1}` via the algorithm in Theorem 4,
page 16 of Dmitry Shirokov's ICCA 2020 paper :cite:`shirokov2020inverse`.
.. versionadded:: 1.4.0
"""
return self.layout._shirokov_inverse(self)

def leftLaInv(self) -> 'MultiVector':
Expand Down Expand Up @@ -792,6 +812,23 @@ def normalInv(self, check=True) -> 'MultiVector':
return self._pick_inv(fallback=False if check else None)

def inv(self) -> 'MultiVector':
r"""Obtain the inverse :math:`M^{-1}`.
This tries a handful of approaches in order:
* If :math:`M \tilde M = |M|^2`, then this uses
:meth:`~MultiVector.normalInv`.
* If :math:`M` is of sufficiently low dimension, this uses
:meth:`~MultiVector.hitzer_inverse`.
* Otherwise, this uses :meth:`~MultiVector.leftLaInv`.
Note that :meth:`~MultiVector.shirokov_inverse` is not used as its
numeric stability is unknown.
.. versionchanged:: 1.4.0
Now additionally tries :meth:`~MultiVector.hitzer_inverse` before
falling back to :meth:`~MultiVector.leftLaInv`.
"""
return self._pick_inv(fallback=True)

leftInv = leftLaInv
Expand Down
109 changes: 109 additions & 0 deletions clifford/numba/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,111 @@
r"""
.. currentmodule:: clifford.numba
===============================================
numba extension support (:mod:`clifford.numba`)
===============================================
.. versionadded:: 1.4.0
This module provides :mod:`numba` extension types :class:`MultiVectorType` and
:class:`LayoutType` corresponding to :class:`~clifford.MultiVector` and
:class:`~clifford.Layout`.
You do not need to import this module to take advantage of these types; they
are needed only directly when writing numba overloads via
:func:`numba.extending.overload` and similar.
As a simple example, the following code defines a vectorized ``up()`` function
for :doc:`CGA </tutorials/cga/index>` ::
from clifford.g3c import *
@numba.njit
def jit_up(x):
return eo + x + 0.5*abs(x)**2*einf
assert up(e1) == jit_up(e1)
Note that a rough equivalent to this particular function is provided elsewhere
as :func:`clifford.tools.g3c.fast_up`.
.. currentmodule:: clifford
Supported operations
--------------------
The following list of operations are supported in a jitted context:
* A limited version of the constructor ``MultiVector(layout, value)``, and
the alias :meth:`layout.MultiVector`.
* :attr:`MultiVector.value`
* :attr:`MultiVector.layout`
* Arithmetic:
* :meth:`MultiVector.__add__`
* :meth:`MultiVector.__sub__`
* :meth:`MultiVector.__mul__`
* :meth:`MultiVector.__xor__`
* :meth:`MultiVector.__or__`
* :meth:`MultiVector.__pow__`
* :meth:`MultiVector.__truediv__`
* :meth:`MultiVector.__invert__`
* :meth:`MultiVector.__pos__`
* :meth:`MultiVector.__neg__`
* :meth:`MultiVector.__call__`
* :meth:`MultiVector.mag2`
* :meth:`MultiVector.__abs__`
* :meth:`MultiVector.normal`
* :meth:`MultiVector.gradeInvol`
* :meth:`MultiVector.conjugate`
Performance considerations
--------------------------
While the resulted jitted code is typically faster, there are two main
performance issues to consider. The first is the startup time of ``@jit``\ ing.
This can be quite substantial, although can be somewhat alleviated by using
the ``cache=True`` argument to :func:`numba.jit`.
The second is the time taken for numba to find the appropriate dispatch loop
given the Python types of its arguments, which adds overhead to every call.
``clifford`` tries as hard as possible to reduce this second overhead, by
using the undocumented ``_numba_type_`` attribute and keeping our own optimized
cache instead of going through the recommended
``@numba.extending.typeof_impl.register(LayoutType)`` mechanism.
However, this overhead can still be slow compared to elementary operations.
The following code is significantly impacted by this overhead::
from clifford.g3c import *
import numba
@numba.njit
def mul(a, b):
return a * b
# 286 ms, ignoring jitting time
x = e1
for i in range(10000):
x = mul(x, x + e2)
as each iteration of the loop pays it again. The overhead can be avoided by
jitting the entire loop::
from clifford.g3c import *
import numba
@numba.njit
def mul(a, b):
return a * b
@numba.njit
def the_loop(x):
for i in range(1000):
x = mul(x, x + e1)
return x
# 2.4 ms, ignoring jitting time
x = the_loop(eq)
"""
from ._multivector import MultiVectorType
from ._layout import LayoutType
6 changes: 3 additions & 3 deletions clifford/tools/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
-----------------------------------------------------------
Given two frames that are related by a orthogonal transform, we seek a rotor
which enacts the transform. Details of the mathematics and pseudo-code used the
which enacts the transform. Details of the mathematics and pseudo-code used to
create the algorithms below can be found at Allan Cortzen's website,
:cite:`ctz-frames`.
Expand Down Expand Up @@ -443,9 +443,9 @@ def rotor_decomp(V: MultiVector, x: MultiVector) -> Tuple[MultiVector, MultiVect
Returns
-------
H : clifford.Multivector
H : clifford.MultiVector
rotor which contains x
U : clifford.Multivector
U : clifford.MultiVector
rotor which leaves x invariant
'''
Expand Down
5 changes: 5 additions & 0 deletions clifford/tools/g3c/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
Generation Methods
--------------------
.. versionchanged:: 1.4.0
Many of these functions accept an ``rng`` arguments, which if provided
should be the result of calling :func:`numpy.random.default_rng` or similar.
.. autosummary::
:toctree: generated/
Expand Down
1 change: 1 addition & 0 deletions docs/api/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ API
operator
transformations
taylor_expansions
numba
1 change: 1 addition & 0 deletions docs/api/numba.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.. automodule:: clifford.numba

0 comments on commit 659f75b

Please sign in to comment.