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 general trig functions via taylor series #371

Merged
merged 27 commits into from
Jan 11, 2021

Conversation

hugohadfield
Copy link
Member

No description provided.

@@ -258,17 +260,73 @@ def general_exp(x, max_order=15):
for i in range(1, max_order):
if np.any(np.abs(tmp.value) > _settings._eps):
tmp = tmp*scaled * (1.0 / i)
result += tmp
result = result + tmp
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the motivation for this change?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Motivation was that without this numba will not JIT our general_exp function:

No implementation of function Function(<built-in function iadd>) found for signature:
iadd(MultiVector(LayoutType(Layout([1, 1, 1], ids=BasisVectorIds.ordered_integers(3), order=BasisBladeOrder.shortlex(3), names=['', 'e1', 'e2', 'e3', 'e12', 'e13', 'e23', 'e123'])), float64), MultiVector(LayoutType(Layout([1, 1, 1], ids=BasisVectorIds.ordered_integers(3), order=BasisBladeOrder.shortlex(3), names=['', 'e1', 'e2', 'e3', 'e12', 'e13', 'e23', 'e123'])), float64))

@@ -589,11 +589,11 @@ def _hitzer_inverse(self):
"""
Performs the inversion operation as described in the paper :cite:`Hitzer_Sangwine_2017`
"""
tot = np.sum(self.sig != 0)
tot = len(self.sig)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note this is needed to get the correct behaviour for the tan test, presumably this is the solution for degenerate metric algebras but it would be nice to see a proof of this

Comment on lines 55 to 70
@pytest.mark.parametrize('np_func,cmath_func', [(np.sin, cmath.sin),
(np.cos, cmath.cos),
(np.tan, cmath.tan),
(np.sinh, cmath.sinh),
(np.cosh, cmath.cosh),
(np.tanh, cmath.tanh)])
def test_trig_Cl010(self, Cl010element, np_func, cmath_func):
"""
This tests the a clifford algebra isomorphic to the complex numbers
"""
for x in np.linspace(0, 2 * np.pi, 10):
for y in np.linspace(0, 2 * np.pi, 10):
complex_mv = x * Cl010element[0] + y * Cl010element[1]
complex_value = x + 1j * y
result = np_func(complex_mv)
assert abs(result.value[0] + 1j * result.value[1] - cmath_func(complex_value)) < 1E-10
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I sent you down the rabbit hole with cmath_func here - np.cos works on complex numbers just fine - I had falsely assumed your tests were using math.cos.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No worries, I'll remove the cmath import and we can just stick to numpy then :)

clifford/__init__.py Outdated Show resolved Hide resolved
@hugohadfield hugohadfield marked this pull request as ready for review October 22, 2020 15:46


@_numba_utils.njit
def general_exp(x, max_order=15):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd argue you can now remove all the general_ prefixes

@eric-wieser
Copy link
Member

This will need a merge / rebase in order to pull in the doc build pinning

@hugohadfield
Copy link
Member Author

I rebased and force pushed, hopefully this now works

@@ -99,7 +99,25 @@ def _newMV(self, newValue=None, *, dtype: np.dtype = None) -> 'MultiVector':
# binary

def exp(self) -> 'MultiVector':
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May as well copy this annotation to all the methods below it

@eric-wieser
Copy link
Member

I think my last comment is wondering whether we can make these look more like general_exp, and whether that improves the numerical stability. For instance, we could replace gamma (2*n+1) with iterated division by 2*n*(2*n+1) or whatever the not-off-by-one version is.

We can always use that for a follow-up PR though, now that this PR adds tests

@hugohadfield
Copy link
Member Author

hugohadfield commented Dec 27, 2020

I think my last comment is wondering whether we can make these look more like general_exp, and whether that improves the numerical stability. For instance, we could replace gamma (2*n+1) with iterated division by 2*n*(2*n+1) or whatever the not-off-by-one version is.

Yes I think this would be a good idea to look at, I am sure that there will be some useful gains

We can always use that for a follow-up PR though, now that this PR adds tests

This is my thoughts too

Copy link
Member

@eric-wieser eric-wieser left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Earlier review was on mobile, apologies. A few small ends to tie up:

  • I've made some doc suggestions above to try and steer users towards how to use this, and to tweak some formatting.
  • This needs a release note, and it's easier to add it now than to add it in later
  • The tests should cover some negative coefficients too!


This file implements various Taylor expansions for useful functions of multivectors.
For some algebra signatures there may exist closed forms of these functions which would likely be faster
and more accurate. Nonetheless having pre-written taylor expansions for the general case is useful.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
and more accurate. Nonetheless having pre-written taylor expansions for the general case is useful.
and more accurate. Nonetheless, having pre-written taylor expansions for the general case is useful.
.. note::
Many of these functions are also exposed as :class:`~clifford.MultiVector` methods,
such as :meth:`clifford.MultiVector.sin`. This means that ``mv.sin()`` or even ``np.sin(mv)`` can be used
as a convenient interface to functions in this module, without having to import it directly.
For example::
>>> from clifford.g3 import *
>>> import numpy as np
>>> np.sin(np.pi*e12/4)
# what does this give?

@_numba_utils.njit
def exp(x, max_order=15):
"""
This implements the series expansion of e**mv where mv is a multivector
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
This implements the series expansion of e**mv where mv is a multivector
This implements the series expansion of :math:`\exp x` where :math:`x` is a multivector

def exp(x, max_order=15):
"""
This implements the series expansion of e**mv where mv is a multivector
The parameter order is the maximum order of the taylor series to use
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The parameter order is the maximum order of the taylor series to use
The parameter `max_order` is the maximum order of the taylor series to use

Comment on lines 102 to 103
Note. It would probably be better to implement this as its own taylor series. This function
is not JITed as currently we do not overload the truediv operator for multivectors.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Note. It would probably be better to implement this as its own taylor series. This function
is not JITed as currently we do not overload the truediv operator for multivectors.
.. note::
It would probably be better to implement this as its own taylor series. This function
is not JITed as currently we do not overload the truediv operator for multivectors.

Comment on lines 139 to 140
Note. It would probably be better to implement this as its own taylor series. This function
is not JITed as currently we do not overload the truediv operator for multivectors.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Note. It would probably be better to implement this as its own taylor series. This function
is not JITed as currently we do not overload the truediv operator for multivectors.
.. note::
It would probably be better to implement this as its own taylor series. This function
is not JITed as currently we do not overload the truediv operator for multivectors.

@@ -0,0 +1,86 @@

from .. import Cl
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Relative imports in tests are usually a bad idea - tests shouldn't assume they are part of the package.

Suggested change
from .. import Cl
from clifford import Cl

(np.cosh, np.sinh),
(np.tanh, lambda x: (1 - np.tanh(x)**2))])
def test_derivatives(self, element, func, deriv_func):
for x in np.linspace(0, 2*np.pi, 10):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do these fare outside [0, 2*pi]? I'd be inclined to expand this to at least include some negative values,

Suggested change
for x in np.linspace(0, 2*np.pi, 10):
for x in np.linspace(-2*np.pi, 2*np.pi, 13):

Comment on lines 23 to 24
>>> np.sin(np.pi*e12/4)
>>> # Produces (0.86867^e12)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
>>> np.sin(np.pi*e12/4)
>>> # Produces (0.86867^e12)
>>> np.sin(np.pi*e12/4)
(0.86867^e12)

@@ -12,6 +12,10 @@ Changes in 1.4.x
* Where possible, ``MultiVector``\ s preserve their data type in the dual, and
the right and left complements.

* A new :mod:`clifford.taylor_expansions` is added to implement taylor series of various
multivector function, starting with common trigonometric functions. These functions are
additionally exposed via a
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
additionally exposed via a
additionally exposed via an incomplete sentence that Hugo forgot to write.

taylor_expansions (:mod:`clifford.taylor_expansions`)
=================================================

.. versionadded:: 1.4.1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
.. versionadded:: 1.4.1
.. versionadded:: 1.4.0

Comment on lines 4 to 6
=================================================
taylor_expansions (:mod:`clifford.taylor_expansions`)
=================================================
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
=================================================
taylor_expansions (:mod:`clifford.taylor_expansions`)
=================================================
=====================================================
taylor_expansions (:mod:`clifford.taylor_expansions`)
=====================================================

@eric-wieser eric-wieser merged commit 1b56672 into pygae:master Jan 11, 2021
@eric-wieser
Copy link
Member

Thanks @hugohadfield 🎉

@eric-wieser eric-wieser added this to the 1.4 release milestone Jul 19, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants