# Changelog¶

## Changes in 1.4.x¶

Python 3.9 is officially supported.

`MultiVector`

is now supported directly within`@numba.njit`

ed code. See the documentation for this feature in the`clifford.numba`

module for more details.New algorithms for the multivector inverse

`MultiVector.inv()`

:Inverting a non-blade multivector in algebras where \(p = q \le 5\) now falls back on the approach described in [HS17] instead of using a linear algebra approach. This algorithm can be used directly via

`MultiVector.hitzer_inverse()`

.An additional method is available,

`MultiVector.shirokov_inverse()`

, which is the arbitrary signature algorithm described in [Shi20].

A new

`clifford.taylor_expansions`

module for Taylor series of various multivector functions, starting with common trigonometric functions. These functions are additionally exposed via methods on`MultiVector`

like`MultiVector.cos()`

.Random functions now accept an

`rng`

keyword argument that accepts the object returned by`numpy.random.default_rng()`

, for deterministic randomness.Projection using

`MultiVector.__call__()`

as`mv(grade)`

no longer raises`ValueError`

for grades not present in the algebra, and instead just returns zero.Some JIT-ed code is now cached when

`clifford`

is imported for the very first time, speeding up subsequent imports.Improved citations in the documentation.

### Bugs fixed¶

Where possible,

`MultiVector`

s preserve their data type in the dual, and the right and left complements.`MVArray`

no longer errantly promotes 0-dimensional arrays to 1-dimensional arrays.`MultiVector`

s with`complex`

coefficients are now printed correctly.`cga.Round.radius()`

is no longer always 1.

### Compatibility notes¶

This will be the last release to support Python 3.5 and 3.6, as the former reached its end-of-life during our last release cycle, and the latter is expected to before our next release.

`clifford.general_exp()`

is deprecated in favor of`clifford.taylor_expansions.exp()`

, although typically`clifford.MultiVector.exp()`

is a better choiceTransparently treating a

`MultiVector`

as a flat array of coefficients is deprecated, and so`mv[i]`

and`len(mv)`

both emit`DeprecationWarning`

s. If the underlying storage order is of interest, use`mv.value[i]`

and`len(mv)`

respectively. To obtain the scalar part of a`MultiVector`

, use`mv[()]`

instead of`mv[0]`

.`Layout.gradeList`

has been removed. If still needed, it can be recovered as an`ndarray`

isntead of a`list`

via the private attribute`layout._basis_blade_order.grades`

(`BasisBladeOrder.grades`

).

## Changes in 1.3.x¶

Python 3.8 is officially supported. 1.2.0 was pinned to a bad numba version that was incompatible with 3.8.

A new

`clifford.operator`

module to contain the previously undocumented`gp()`

,`op()`

, and`ip()`

helpers.A new

`clifford.transformations`

module for linear transformations.Two new Predefined Algebras,

`clifford.dpga`

and`clifford.dg3c`

.Improvements throughout the documentation:

Better overall structure, visible in the docs sidebar.

New tutorials for Conformal Geometric Algebra on visualization and applications.

New tutorial on Working with custom algebras.

New tutorial on Linear transformations.

New links at the top of each notebook tutorial, to run examples from the browser.

Faster algebra construction.

`Cl(3)`

is now 100× faster, and`Cl(6)`

is 20× faster. This is achieved by deferring product JIT compilation until the product is used for the first time.Additional testing and assorted improvements for

`clifford.tools.g3c`

:`closest_point_on_circle_from_line()`

has now been implemented roughly following the procedure described in Appendix A of Andreas Aristidou’s PhD thesis.`closest_point_on_line_from_circle()`

has now also been added, projecting the result of`closest_point_on_circle_from_line()`

to the line.

`clifford.ugly()`

now results in less ugly output for Predefined Algebras.

### Bugs fixed¶

`MultiVector.meet()`

no longer produces zero erroneously.`mv[e1 + e12]`

now raises`ValueError`

, rather than being interpreted as`mv[e1]`

.`ip()`

(the inner product) no longer performs the outer product.`Layout.parse_multivector()`

now throws`SyntaxError`

on invalid input, rather than silenltly producing nonsense.`Layout.parse_multivector()`

supports basis vector names which do not start with e.-
`val_midpoint_between_lines()`

now handles the case that the two lines are touching.`val_fit_circle()`

now correctly selects the first and second eigenvalue regardless of order.`sphere_beyond_plane()`

now tested and correct.`sphere_behind_plane()`

now tested and correct.`val_unsign_sphere()`

is now jitted, as it should have been from the start.`get_nearest_plane_point()`

correctly returns the conformal point rather than the 3D point.

### Compatibility notes¶

`clifford.grades_present`

is deprecated in favor of`MultiVector.grades()`

, the latter of which now takes an`eps`

argument.`del mv[i]`

is no longer legal, the equivalent`mv[i] = 0`

should be used instead.`Layout.dict_to_multivector`

has been removed. It was accidentally broken in 1.0.5, so there is little point deprecating it.`Layout.basis_names()`

now returns a`list`

of`str`

, rather than a numpy array of`bytes`

. The result now matches the construction order, rather than being sorted alphabetically. The order of`Layout.metric()`

has been adjusted for consistency.The

`imt_prod_mask`

,`omt_prod_mask`

, and`lcmt_prod_mask`

attributes of`Layout`

objects have been removed, as these were an unnecessary intermediate computation that had no need to be public.Some functions in

`clifford.tools.g3c`

have been renamed:`closest_points_on_circles`

has been renamed to`iterative_closest_points_on_circles()`

.`closest_points_circle_line`

has been renamed to`iterative_closest_points_circle_line()`

.`furthest_points_on_circles`

has been renamed to`iterative_furthest_points_on_circles()`

.

While this release is compatible with

`numba`

version 0.49.0, it is recommended to use 0.48.0 which does not emit as many warnings. See the Installation instructions for how to follow this guidance.

### Patch releases¶

1.3.1: Added compatibility with

`numba`

version 0.50.0.

## Changes in 1.2.x¶

`layout.isconformal`

,`layout.einf`

, and`layout.eo`

, which were added in 1.0.4, have been removed. The first can now be spelt`isinstance(layout, clifford.ConformalLayout)`

, and the other properties now exist only on`ConformalLayout`

objects.`MultiVector.left_complement()`

has been added for consistency with`MultiVector.right_complement()`

.A new

`clifford.tools.classify`

module has been added for classifying blades.`Layout`

objects print slightly more cleanly in Jupyter notebooks.`Layout.scalar`

is now integral rather than floating point

### Bugs fixed¶

`pow(mv, 0)`

gives the right result`nan`

is now printed correctly when it appears in multivectors. Previously it was hidden`MultiVector.right_complement()`

no longer performs the left complement.`MultiVector.vee()`

has been corrected to have the same sign as`MultiVector.meet()`

### Compatibility notes¶

`Layout.scalar`

is now integral rather than floating point, to match`Layout.pseudoScalar`

.

## Changes in 1.1.x¶

Restores

`layout.gmt`

,`Layout.omt`

,`Layout.imt`

, and`Layout.lcmt`

. A few releases ago, these existed but were dense. For memory reasons, they were then removed entirely. They have now been reinstated as`sparse.COO`

matrix objects, which behave much the same as the original dense arrays.`MultiVector`

s preserve their data type in addition, subtraction, and products. This means that integers remain integers until combined with floats. Note that this means in principle integer overflow is possible, so working with floats is still recommended. This also adds support for floating point types of other precision, such as`np.float32`

.`setup.py`

is now configured such that`pip2 install clifford`

will not attempt to download this version, since it does not work at all on python 2.Documentation now includes examples of

`pyganja`

visualizations.

### Compatibility notes¶

### Bugs fixed¶

`mv[(i, j)]`

would sometimes fail if the indices were not in canonical order.`mv == None`

and`layout == None`

would crash rather than return`False`

.`blade.isVersor()`

would return`False`

.`layout.blades_of_grade(0)`

would not return the list it claimed to return.

### Internal changes¶

Switch to

`pytest`

for testing.Enable code coverage.

Split into smaller files.

Remove python 2 compatibility code, which already no longer worked.

## Changes 0.6-0.7¶

Added a real license.

Convert to NumPy instead of Numeric.

## Changes 0.5-0.6¶

`join()`

and`meet()`

actually work now, but have numerical accuracy problemsadded

`clean()`

to`MultiVector`

added

`leftInv()`

and`rightInv()`

to`MultiVector`

moved

`pseudoScalar()`

and`invPS()`

to`MultiVector`

(so we can derive new classes from`MultiVector`

)changed all of the instances of creating a new MultiVector to create an instance of

`self.__class__`

for proper inheritancefixed bug in laInv()

fixed the massive confusion about how dot() works

added left-contraction

fixed embarrassing bug in gmt generation

added

`normal()`

and`anticommutator()`

methodsfixed dumb bug in

`elements()`

that limited it to 4 dimensions

## Acknowledgements¶

Konrad Hinsen fixed a few bugs in the conversion to numpy and adding some unit tests.