Module Documentation¶
Algebra¶
- class kingdon.algebra.Algebra(p: int = 0, q: int = 0, r: int = 0, signature: ~numpy.ndarray = None, start_index: int = None, registry: dict = <factory>, numspace: dict = <factory>, cse: bool = True, graded: bool = False, wrapper: ~collections.abc.Callable = None, codegen_symbolcls: object = <bound method RationalPolynomial.fromname of <class 'kingdon.polynomial.RationalPolynomial'>>, simp_func: ~collections.abc.Callable = <function Algebra.<lambda>>)[source]¶
A Geometric (Clifford) algebra with
p
positive dimensions,q
negative dimensions, andr
null dimensions.The default settings of
cse = simplify = True
usually strike a good balance between initiation times and subsequent code execution times.- Parameters:
p – number of positive dimensions.
q – number of negative dimensions.
r – number of null dimensions.
cse – If
True
(default), attempt Common Subexpression Elimination (CSE) on symbolically optimized expressions.graded – If
True
(default isFalse
), perform binary and unary operations on a graded basis. This will still be more sparse than computing with a full multivector, but not as sparse as possible. It does however, vastly reduce the number of possible expressions that have to be symbolically optimized.simplify – If
True
(default), we attempt to simplify as much as possible. Setting this toFalse
will reduce the number of calls to simplify. However, it seems thatTrue
is still faster, probably because it keeps sympy expressions from growing too large, which makes both symbolic computations and printing into a python function slower.wrapper – A function that is always applied to the generated functions as a decorator. For example, using
numba.njit
as a wrapper will ensure that all kingdon code is jitted using numba.codegen_symbolcls – The symbol class used during codegen. By default, this is our own fast
RationalPolynomial
class.simp_func – This function is applied as a filter function to every multivector coefficient.
- acp: OperatorDict¶
- add: OperatorDict¶
- bivector(*args, **kwargs) MultiVector [source]¶
- classmethod codegen_symbolcls(name)¶
- conjugate: UnaryOperatorDict¶
- cp: OperatorDict¶
- div: OperatorDict¶
- evenmv(*args, **kwargs) MultiVector [source]¶
Create a new
MultiVector
in the even subalgebra.
- property frame: list¶
The set of orthogonal basis vectors, \(\{ e_i \}\). Note that for a frame linear independence suffices, but we already have orthogonal basis vectors so why not use those?
- gp: OperatorDict¶
- graph(*subjects, graph_widget=<class 'kingdon.graph.GraphWidget'>, **options)[source]¶
The graph function outputs
ganja.js
renders and is meant for use in jupyter notebooks. The syntax of the graph function will feel familiar to users ofganja.js
: all position arguments are considered as subjects to graph, while all keyword arguments are interpreted as options toganja.js
’sAlgebra.graph
method.Example usage:
alg.graph( 0xD0FFE1, [A,B,C], 0x224488, A, "A", B, "B", C, "C", lineWidth=3, grid=1, labels=1 )
Will create
If a function is given to
Algebra.graph
then it is called without arguments. This can be used to make animations in a manner identical toganja.js
.Example usage:
def graph_func(): return [ 0xD0FFE1, [A,B,C], 0x224488, A, "A", B, "B", C, "C" ] alg.graph( graph_func, lineWidth=3, grid=1, labels=1 )
- Parameters:
*subjects – Subjects to be graphed. Can be strings, hexadecimal colors, (lists of) MultiVector, (lists of) callables.
**options – Options passed to
ganja.js
’sAlgebra.graph
.
- hodge: UnaryOperatorDict¶
- property indices_for_grade¶
Mapping from the grades to the indices for that grade. E.g. in 2D VGA, this returns
{0: (0,), 1: (1, 2), 2: (3,)}
- property indices_for_grades¶
Mapping from a sequence of grades to the corresponding indices. E.g. in 2D VGA, this returns
{(): (), (0,): (0,), (1,): (1, 2), (2,): (3,), (0, 1): (0, 1, 2), (0, 2): (0, 3), (1, 2): (1, 2, 3), (0, 1, 2): (0, 1, 2, 3)}
- inv: UnaryOperatorDict¶
- involute: UnaryOperatorDict¶
- ip: OperatorDict¶
- lc: OperatorDict¶
- property matrix_basis¶
- multivector(*args, **kwargs) MultiVector [source]¶
Create a new
MultiVector
.
- neg: UnaryOperatorDict¶
- normsq: UnaryOperatorDict¶
- oddmv(*args, **kwargs) MultiVector [source]¶
Create a new
MultiVector
of odd grades. (There is technically no such thing as an odd subalgebra, but otherwise this is similar toevenmv
.)
- op: OperatorDict¶
- outercos: UnaryOperatorDict¶
- outerexp: UnaryOperatorDict¶
- outersin: UnaryOperatorDict¶
- outertan: UnaryOperatorDict¶
- polarity: UnaryOperatorDict¶
- pseudobivector(*args, **kwargs) MultiVector [source]¶
- pseudoquadvector(*args, **kwargs) MultiVector [source]¶
- pseudoscalar(*args, **kwargs) MultiVector [source]¶
- pseudotrivector(*args, **kwargs) MultiVector [source]¶
- pseudovector(*args, **kwargs) MultiVector [source]¶
- purevector(*args, grade, **kwargs) MultiVector [source]¶
Create a new
MultiVector
of a specific grade.- Parameters:
grade – Grade of the mutivector to create.
- quadvector(*args, **kwargs) MultiVector [source]¶
- rc: OperatorDict¶
- property reciprocal_frame: list¶
The reciprocal frame is a set of vectors \(\{ e^i \}\) that satisfies \(e^i \cdot e_j = \delta^i_j\) with the frame vectors \(\{ e_i \}\).
- register(expr=None, /, *, name=None, symbolic=False)[source]¶
Register a function with the algebra to optimize its execution times.
The function must be a valid GA expression, not an arbitrary python function.
Example:
@alg.register def myexpr(a, b): return a @ b @alg.register(symbolic=True) def myexpr(a, b): return a @ b
With default settings, the decorator will ensure that every GA unary or binary operator is replaced by the corresponding numerical function, and produces numerically much more performant code. The speed up is particularly notible when e.g. self.wrapper=numba.njit, because then the cost for all the python glue surrounding the actual computation has to be paid only once.
When symbolic=True the expression is symbolically optimized before being turned into a numerical function. Beware that symbolic optimization of longer expressions (currently) takes exorbitant amounts of time, and often isn’t worth it if the end goal is numerical computation.
- Parameters:
expr – Python function of a valid kingdon GA expression.
name – (optional) name by which the function will be known to the algebra. By default, this is the expr.__name__.
symbolic – (optional) If true, the expression is symbolically optimized. By default this is False, given the cost of optimizing large expressions.
- reverse: UnaryOperatorDict¶
- rp: OperatorDict¶
- scalar(*args, **kwargs) MultiVector [source]¶
- simp_func()¶
- sp: OperatorDict¶
- sqrt: UnaryOperatorDict¶
- sub: OperatorDict¶
- trivector(*args, **kwargs) MultiVector [source]¶
- unhodge: UnaryOperatorDict¶
- unpolarity: UnaryOperatorDict¶
- vector(*args, **kwargs) MultiVector [source]¶
- class kingdon.algebra.BladeDict(algebra: Algebra, lazy: bool = False)[source]¶
Dictionary of basis blades. Use getitem or getattr to retrieve a basis blade from this dict, e.g.:
alg = Algebra(3, 0, 1) blade_dict = BladeDict(alg, lazy=True) blade_dict['e03'] blade_dict.e03
When lazy=True, the basis blade is only initiated when requested. This is done for performance in higher dimensional algebras.
MultiVector¶
- class kingdon.multivector.MultiVector(algebra: 'Algebra', values=None, keys=None, *, name=None, grades=None, symbolcls=<class 'sympy.core.symbol.Symbol'>, **items)[source]¶
- acp(other)[source]¶
Calculate the anti-commutator product of
x := self
andy := other
:x.cp(y) = 0.5*(x*y+y*x)
.
- asfullmv(canonical=True)[source]¶
Returns a full version of the same multivector.
- Parameters:
canonical – If True (default) the values are in canonical order, even if the mutivector was already dense.
- cp(other)[source]¶
Calculate the commutator product of
x := self
andy := other
:x.cp(y) = 0.5*(x*y-y*x)
.
- dual(kind='auto')[source]¶
Compute the dual of self. There are three different kinds of duality in common usage. The first is polarity, which is simply multiplying by the inverse PSS. This is the only game in town for non-degenerate metrics (Algebra.r = 0). However, for degenerate spaces this no longer works, and we have two popular options: Poincaré and Hodge duality.
By default,
kingdon
will use polarity in non-degenerate spaces, and Hodge duality for spaces with Algebra.r = 1. For spaces with r > 2, little to no literature exists, and you are on your own.- Parameters:
kind – if ‘auto’ (default),
kingdon
will try to determine the best dual on the basis of the signature of the space. See explenation above. To ensure polarity, usekind='polarity'
, and to ensure Hodge duality, usekind='hodge'
.
- filter(func=None) MultiVector [source]¶
Returns a new multivector containing only those elements for which func was true-ish. If no function was provided, use the simp_func of the Algebra.
- property free_symbols¶
- classmethod fromkeysvalues(algebra, keys, values)[source]¶
Initiate a multivector from a sequence of keys and a sequence of values.
- classmethod frommatrix(algebra, matrix)[source]¶
Initiate a multivector from a matrix. This matrix is assumed to be generated by
asmatrix
, and thus we only read the first column of the input matrix.
- grade(*grades)[source]¶
Returns a new
MultiVector
instance with only the selected grades from self.- Parameters:
grades – tuple or ints, grades to select.
- property grades¶
Tuple of the grades present in self.
- property issymbolic¶
True if this mv contains Symbols, False otherwise.
- itermv(axis=None) Generator[MultiVector, None, None] [source]¶
Returns an iterator over the multivectors within this multivector, if it is a multidimensional multivector. For example, if you have a pointcloud of N points, itermv will iterate over these points one at a time.
- Parameters:
axis – Axis over which to iterate. Default is to iterate over all possible mv.
- map(func) MultiVector [source]¶
Returns a new multivector where func has been applied to all the values.
- proj(other)[source]¶
Project
x := self
ontoy := other
:x @ y = (x | y) * ~y
. For correct behavior,x
andy
should be normalized (k-reflections).
- property shape¶
Return the shape of the .values() attribute of this multivector.
Codegen¶
The codegen module generates python functions from operations
between/on purely symbolic MultiVector
objects.
As a general rule, these functions take in pure symbolic
MultiVector
objects and return a tuple of keys
present in the output, and a pure python function which represents the
respective operation.
E.g. codegen_gp()
computes the geometric product
between two multivectors for the specific non-zero basis blades present in
the input.
- class kingdon.codegen.CodegenOutput(keys_out: Tuple[int], func: Callable)[source]¶
Output of a codegen function.
- Parameters:
keys_out – tuple with the output blades in binary rep.
func – callable that takes (several) sequence(s) of values returns a tuple of
len(keys_out)
.
- class kingdon.codegen.Fraction(numer, denom)¶
Tuple representing a fraction.
- denom¶
Alias for field number 1
- numer¶
Alias for field number 0
- class kingdon.codegen.LambdifyInput(funcname: str, args: dict, expr_dict: dict, dependencies: list)[source]¶
Strike package for the Lambdify function.
- class kingdon.codegen.TermTuple(key_out: int, keys_in: Tuple[int], sign: int, values_in: Tuple['sympy.core.symbol.Symbol'], termstr: str)[source]¶
TermTuple represents a single monomial in a product of multivectors.
- Parameters:
key_out – is the basis blade to which this monomial belongs.
keys_in – are the input basis blades in this monomial.
sign – Sign of the monomial.
values_in – Input values. Typically, tuple of
sympy.core.symbol.Symbol
.termstr – The string representation of this monomial, e.g. ‘-x*y’.
- values_in: Tuple['sympy.core.symbol.Symbol']¶
Alias for field number 3
- kingdon.codegen.codegen_acp(x, y)[source]¶
Generate the anti-commutator product of
x
andy
:x.acp(y) = 0.5*(x*y+y*x)
.- Returns:
tuple of keys in binary representation and a lambda function.
- kingdon.codegen.codegen_cp(x, y)[source]¶
Generate the commutator product of
x
andy
:x.cp(y) = 0.5*(x*y-y*x)
.- Returns:
tuple of keys in binary representation and a lambda function.
- kingdon.codegen.codegen_gp(x, y)[source]¶
Generate the geometric product between
x
andy
.- Parameters:
x – Fully symbolic
MultiVector
.y – Fully symbolic
MultiVector
.
- Returns:
tuple with integers indicating the basis blades present in the product in binary convention, and a lambda function that perform the product.
- kingdon.codegen.codegen_hitzer_inv(x, symbolic=False)[source]¶
Generate code for the inverse of
x
using the Hitzer inverse, which works up to 5D algebras.
- kingdon.codegen.codegen_involutions(x, invert_grades=(2, 3))[source]¶
Codegen for the involutions of Clifford algebras: reverse, grade involute, and Clifford involution.
- Parameters:
invert_grades – The grades that flip sign under this involution mod 4, e.g. (2, 3) for reversion.
- kingdon.codegen.codegen_ip(x, y, diff_func=<built-in function abs>)[source]¶
Generate the inner product of
x
andy
.- Parameters:
diff_func – How to treat the difference between the binary reps of the basis blades. if
abs
, compute the symmetric inner product. Whenlambda x: -x
this function generates left-contraction, and whenlambda x: x
, right-contraction.- Returns:
tuple of keys in binary representation and a lambda function.
- kingdon.codegen.codegen_lc(x, y)[source]¶
Generate the left-contraction of
x
andy
.- Returns:
tuple of keys in binary representation and a lambda function.
- kingdon.codegen.codegen_op(x, y)[source]¶
Generate the outer product of
x
andy
:x.op(y) = x ^ y
.- X:
MultiVector
- Y:
MultiVector
- Returns:
dictionary with integer keys indicating the corresponding basis blade in binary convention, and values which are a 3-tuple of indices in x, indices in y, and a lambda function.
- kingdon.codegen.codegen_product(x, y, filter_func=None, sign_func=None, keyout_func=<built-in function xor>)[source]¶
Helper function for the codegen of all product-type functions.
- Parameters:
x – Fully symbolic
MultiVector
.y – Fully symbolic
MultiVector
.filter_func – A condition which should be true in the preprocessing of terms. Input is a TermTuple.
sign_func – function to compute sign between terms. E.g. algebra.signs[ei, ej] for metric dependent products. Input: 2-tuple of blade indices, e.g. (ei, ej).
keyout_func
- kingdon.codegen.codegen_proj(x, y)[source]¶
Generate the projection of
x
ontoy
: \((x \cdot y) \widetilde{y}\).- Returns:
tuple of keys in binary representation and a lambda function.
- kingdon.codegen.codegen_rc(x, y)[source]¶
Generate the right-contraction of
x
andy
.- Returns:
tuple of keys in binary representation and a lambda function.
- kingdon.codegen.codegen_rp(x, y)[source]¶
Generate the regressive product of
x
andy
:, \(x \vee y\).- Parameters:
x
y
- Returns:
tuple of keys in binary representation and a lambda function.
- kingdon.codegen.codegen_shirokov_inv(x, symbolic=False)[source]¶
Generate code for the inverse of
x
using the Shirokov inverse, which is works in any algebra, but it can be expensive to compute.
- kingdon.codegen.codegen_sp(x, y)[source]¶
Generate the scalar product of
x
andy
.- Returns:
tuple of keys in binary representation and a lambda function.
- kingdon.codegen.codegen_sqrt(x)[source]¶
Take the square root using the study number approach as described in https://doi.org/10.1002/mma.8639
- kingdon.codegen.codegen_sw(x, y)[source]¶
Generate the conjugation of
y
byx
: \(x y \widetilde{x}\).- Returns:
tuple of keys in binary representation and a lambda function.
- kingdon.codegen.do_codegen(codegen, *mvs) CodegenOutput [source]¶
- Parameters:
codegen – callable that performs codegen for the given
mvs
. This can be any callable that returns either aMultiVector
, a dictionary, or an instance ofCodegenOutput
.mvs – Any remaining positional arguments are taken to be symbolic
MultiVector
’s.
- Returns:
Instance of
CodegenOutput
.
- kingdon.codegen.func_builder(res_vals: defaultdict, *mvs, funcname: str) CodegenOutput [source]¶
Build a Python function for the product between given multivectors.
- Parameters:
res_vals – Dict to be converted into a function. The keys correspond to the basis blades in binary, while the values are strings to be converted into source code.
mvs – all the multivectors that the resulting function is a product of.
funcname – Name of the function. Be aware: if a function by that name already existed, it will be overwritten.
- Returns:
tuple of output keys of the callable, and the callable.
- kingdon.codegen.lambdify(args: dict, exprs: list, funcname: str, dependencies: tuple = None, printer=<class 'sympy.printing.lambdarepr.LambdaPrinter'>, dummify=False, cse=False)[source]¶
Function that turns symbolic expressions into Python functions. Heavily inspired by
sympy
’s function by the same name, but adapted for the needs ofkingdon
.Particularly, this version gives us more control over the names of the function and its arguments, and is more performant, particularly when the given expressions are strings.
Example usage:
alg = Algebra(2) a = alg.multivector(name='a') b = alg.multivector(name='b') args = {'A': a.values(), 'B': b.values()} exprs = tuple(codegen_cp(a, b).values()) func = lambdify(args, exprs, funcname='cp', cse=False)
This will produce the following code:
def cp(A, B): [a, a1, a2, a12] = A [b, b1, b2, b12] = B return (+a1*b2-a2*b1,)
It is recommended not to call this function directly, but rather to use
do_codegen()
which provides a clean API around this function.- Parameters:
args – dictionary of type dict[str | Symbol, tuple[Symbol]].
exprs – tuple[Expr]
funcname – string to be used as the bases for the name of the function.
dependencies – These are extra expressions that can be provided such that quantities can be precomputed. For example, in the inverse of a multivector, this is used to compute the scalar denominator only once, after which all values in expr are multiplied by it. When
cse = True
, these dependencies are also included in the CSE process.cse – If
True
(default), CSE is applied to the expressions and dependencies. This typically greatly improves performance and reduces numba’s initialization time.
- Returns:
Function that represents that can be used to calculate the values of exprs.
- kingdon.codegen.power_supply(x: MultiVector, exponents: Tuple[int, ...], operation: Callable[['MultiVector', 'MultiVector'], 'MultiVector'] = <built-in function mul>)[source]¶
Generates powers of a given multivector using the least amount of multiplications. For example, to raise a multivector \(x\) to the power \(a = 15\), only 5 multiplications are needed since \(x^{2} = x * x\), \(x^{3} = x * x^2\), \(x^{5} = x^2 * x^3\), \(x^{10} = x^5 * x^5\), \(x^{15} = x^5 * x^{10}\). The
power_supply
usesAdditionChains
to determine these shortest chains.When called with only a single integer, e.g.
power_supply(x, 15)
, iterating over it yields the above sequence in order; ending with \(x^{15}\).When called with a sequence of integers, the generator instead returns only the requested terms.
- Parameters:
x – The MultiVector to be raised to a power.
exponents – When an
int
, this generates the shortest possible way to get to \(x^a\), where \(x\)
Operator dicts¶
- class kingdon.operator_dict.OperatorDict(name: str, codegen: Callable, algebra: Algebra)[source]¶
A dict-like object which performs codegen of a particular operator, and caches the result for future use. For example, to generate the geometric product, we create an OperatorDict as follows:
alg = Algebra(3, 0, 1) gp = OperatorDict('gp', codegen=codegen_gp, algebra=alg)
Here,
codegen_gp
is a function that outputs the keys of the result, and a callable that produces the corresponding values. SeeCodegenOutput
for more info.
Matrix reps¶
This module contains support functions to turn
MultiVector
’s into matrices.
This follows the approach outlined in Graded Symmetry Groups: Plane and Simple, section 10. See the paper for more details.
- kingdon.matrixreps.expr_as_matrix(expr: Callable, *inputs, res_like: MultiVector = None)[source]¶
This represents any GA expression as a matrix. To illustrate by example, we might want to represent the multivector equation y = R >> x as a matrix equation y = Ax. To obtain A, call this function as follows:
alg = Algebra(3, 0, 1) R = alg.evenmv(name='R') x = alg.vector(name='x') A, y = expr_as_matrix(lambda R, x: R >> x, R, x)
In order to build the matrix rep the input expr is evaluated, so make sure the inputs to the expression are given in the correct order. The last of the positional arguments is assumed to be the vector x.
- Expr:
Callable representing a valid GA expression. Can also be a
OperatorDict
.- Inputs:
All positional arguments are consider symbolic input arguments to expr. The last of these is assumed to represent the vector x in y = Ax.
- Res_like:
optional multivector corresponding to the desired output. If None, then the full output is returned. However, if only a subsegment of the output is desired, provide a multivector with the desired shape. In the example above setting, res_like = alg.vector(e1=1) would mean only the e1 component of the matrix is returned. This does not have to be a symbolic multivector, only the keys are checked.
- Returns:
This function returns the matrix representation, and the result of applying the expression to the input.
- kingdon.matrixreps.matrix_rep(p=0, q=0, r=0)[source]¶
Create the matrix reps of all the basis blades of an algebra. These are selected such that the entries in the first column of the matrix have positive sign, and thus matrix-matrix multiplication is identical to matrix-vector multiplication.
- Parameters:
p – number of positive dimensions.
q – number of negative dimensions.
r – number of null dimensions.
- Returns:
sequence of matrix reps for the basis-blades.
- kingdon.matrixreps.ordering_matrix(Rs)[source]¶
Matrix reps are determined up to similarity transform. But not all similarity transforms are equal. This function creates the one similarity transform that gives all entries in the first column of the matrix a positive sign. In doing so, matrix-matrix multiplication is identical to matrix-vector multiplication.
- Parameters:
Rs – sequence of matrix reps for all the basis blades of an algebra.
- Returns:
The similarity transform to beat all similarity transforms.
Graph¶
- class kingdon.graph.GraphWidget(**kwargs: Any)[source]¶
- algebra¶
A trait whose value must be an instance of a specified class.
The value can also be an instance of a subclass of the specified class.
Subclasses can declare default classes by overriding the klass attribute
- cayley¶
An instance of a Python list.
- draggable_points¶
An instance of a Python list.
- draggable_points_idxs¶
An instance of a Python list.
- get_cayley¶
- get_draggable_points¶
- get_draggable_points_idxs¶
- get_key2idx¶
- get_pre_subjects¶
- get_signature¶
- get_subjects¶
- inplacereplace(old_subjects, new_subjects: List[Tuple[int, dict]])[source]¶
Given the old and the new subjects, replace the values inplace iff they have changed.
- key2idx¶
An instance of a Python dict.
One or more traits can be passed to the constructor to validate the keys and/or values of the dict. If you need more detailed validation, you may use a custom validator method.
Changed in version 5.0: Added key_trait for validating dict keys.
Changed in version 5.0: Deprecated ambiguous
trait
,traits
args in favor ofvalue_trait
,per_key_traits
.
- options¶
An instance of a Python dict.
One or more traits can be passed to the constructor to validate the keys and/or values of the dict. If you need more detailed validation, you may use a custom validator method.
Changed in version 5.0: Added key_trait for validating dict keys.
Changed in version 5.0: Deprecated ambiguous
trait
,traits
args in favor ofvalue_trait
,per_key_traits
.
- pre_subjects¶
An instance of a Python list.
- raw_subjects¶
An instance of a Python list.
- signature¶
An instance of a Python list.
- subjects¶
An instance of a Python list.
Rational Polynomial¶
- class kingdon.polynomial.RationalPolynomial(numer, denom=None)[source]¶
- denom: Polynomial¶
- numer: Polynomial¶