magnus.expansionterms
expansionterms.py
Generate the terms of the Magnus expansion symbolically, to any order.
The numerical core in magnus.magnus writes the coefficients of each commutator
group out explicitly in Python through order 6, and builds orders 7 to 10 from the same
recursion when it runs; the ceiling is magnus.magnus.MAGNUS_EXP_ORDER_MAX, set by how
far the table of group factors reaches. This module derives those same terms from the
recursion itself, in exact rational arithmetic, at any order – so the built-in ones can
be checked rather than trusted, and so an order beyond the implemented ceiling can
still be inspected on paper.
The recursion is the standard Bernoulli-number one [1] (in the \(B_1 = -1/2\) convention):
where the \(S_n^{(j)}\) are themselves defined recursively,
so that every term of \(\Omega_n\) is a nested commutator of lower-order \(\Omega_m\) with \(A\), carrying a rational coefficient. Because \(B_j = 0\) for every odd \(j \geq 3\), whole groups drop out: only \(j = 1, 2, 4, 6, \ldots\) contribute.
This is the same form the numerical core implements, deliberately. Writing \(\Omega_n\) instead as time-ordered multiple integrals of \(A\) alone is the other common presentation, but it does not correspond to anything the code evaluates, so it would be of no use for checking the implementation.
The number of terms grows quickly – 1 at order 1, 9 at order 6, 33 at order 8, 129 at
order 10, the counts count_terms() returns – which is why the implemented ceiling
is a deliberate choice rather than an oversight. See Magnus Expansion Terms to Any Order for the derivation, the expansion printed out,
and worked examples.
References
Routine listings
bernoulli - Bernoulli number B_n as an exact Fraction
bernoulli_factor - The coefficient B_j / j! of a commutator group
omega_terms - Terms of Omega_n, as (coefficient, nested-commutator) pairs
magnus_terms - omega_terms for every order up to the one requested
format_term - One term as a readable string
print_magnus_terms - The expansion, printed order by order
count_terms - Number of terms in Omega_n, without building them
Attributes
Functions
|
Returns the Bernoulli number \(B_n\) as an exact |
|
Returns \(B_j / j!\), the coefficient multiplying the \(j\)-th commutator |
|
Returns the terms of \(\Omega_n\) for |
|
Returns |
|
Returns the number of terms in \(\Omega_n\). |
|
Renders one term as a readable string. |
|
Prints the Magnus expansion, order by order, up to |
Module Contents
- magnus.expansionterms.bernoulli(n: int) fractions.Fraction[source]
Returns the Bernoulli number \(B_n\) as an exact
fractions.Fraction.Uses the \(B_1 = -1/2\) convention, which is the one the Magnus recursion above is written in, and computes from the defining recursion
\[B_m = -\frac{1}{m+1} \sum_{j=0}^{m-1} \binom{m+1}{j} B_j ,\]in exact rational arithmetic, so the result is not subject to rounding at any order. Every odd \(B_n\) with \(n \geq 3\) comes out exactly zero.
Added in version 1.0.0.
- Parameters:
n (int) – Index of the Bernoulli number; must be >= 0.
- Returns:
\(B_n\).
- Return type:
- Raises:
ValueError – If
nis negative.
Examples
import magnus.expansionterms as et [str(et.bernoulli(n)) for n in range(9)]
['1', '-1/2', '1/6', '0', '-1/30', '0', '1/42', '0', '-1/30']
- magnus.expansionterms.bernoulli_factor(j: int) fractions.Fraction[source]
Returns \(B_j / j!\), the coefficient multiplying the \(j\)-th commutator group in the Magnus recursion.
These are the numbers the numerical core hard-codes: \(B_1/1! = -1/2\), \(B_2/2! = 1/12\), \(B_4/4! = -1/720\), \(B_6/6! = 1/30240\).
Added in version 1.0.0.
- Parameters:
j (int) – Index of the commutator group; must be >= 0.
- Returns:
\(B_j / j!\).
- Return type:
- Raises:
ValueError – If
jis negative. The check lives inbernoulli(), which this calls.
Examples
import magnus.expansionterms as et {j: str(et.bernoulli_factor(j)) for j in (1, 2, 4, 6)}
{1: '-1/2', 2: '1/12', 4: '-1/720', 6: '1/30240'}
- magnus.expansionterms.omega_terms(order: int) Tuple[Term, ...][source]
Returns the terms of \(\Omega_n\) for
n = order.Each term is a
(coefficient, word)pair: an exactfractions.Fractionand a nested commutator built from'A'and('Om', m)leaves via('c', X, Y)nodes. The whole of \(\Omega_n\) is the integral of the sum of these terms, as in the module docstring.Odd Bernoulli numbers above \(B_1\) vanish, so the \(j = 3, 5, 7, \ldots\) groups contribute nothing and are skipped rather than generated and discarded.
Added in version 1.0.0.
- Parameters:
order (int) – Order \(n\) of the term; must be >= 1.
- Returns:
The terms of \(\Omega_n\). A word is a nested commutator, written as a tuple, except at
order=1, where the single term is(1, 'A')– the word is the bare string, the integrand of \(\Omega_1 = \int A\).- Return type:
tuple of (fractions.Fraction, Word)
- Raises:
ValueError – If
orderis less than 1.
Examples
import magnus.expansionterms as et for coeff, word in et.omega_terms(3): print(f"{str(coeff):>6s} {et.format_term((coeff, word), with_coeff=False)}")
-1/2 [Om_2, A] 1/12 [Om_1, [Om_1, A]]
- magnus.expansionterms.magnus_terms(max_order: int) Dict[int, Tuple[Term, ...]][source]
Returns
omega_terms()for every order from 1 up tomax_order.Added in version 1.0.0.
- Parameters:
max_order (int) – Highest order to generate; must be >= 1.
- Returns:
Maps each order \(n\) to the terms of \(\Omega_n\).
- Return type:
- Raises:
ValueError – If
max_orderis less than 1.
Examples
import magnus.expansionterms as et {n: len(terms) for n, terms in et.magnus_terms(8).items()}
{1: 1, 2: 1, 3: 2, 4: 3, 5: 5, 6: 9, 7: 17, 8: 33}
- magnus.expansionterms.count_terms(order: int) int[source]
Returns the number of terms in \(\Omega_n\).
Builds the terms and counts them, so the count reflects the collection of like terms rather than the raw size of the recursion.
Added in version 1.0.0.
- Parameters:
order (int) – Order \(n\); must be >= 1.
- Returns:
Number of distinct commutator terms in \(\Omega_n\).
- Return type:
- Raises:
ValueError – If
orderis less than 1. The check lives inomega_terms(), which this calls to build the terms it counts.
Examples
import magnus.expansionterms as et {n: et.count_terms(n) for n in range(1, 11)}
{1: 1, 2: 1, 3: 2, 4: 3, 5: 5, 6: 9, 7: 17, 8: 33, 9: 65, 10: 129}
- magnus.expansionterms.format_term(term: Term, with_coeff: bool = True) str[source]
Renders one term as a readable string.
Added in version 1.0.0.
- Parameters:
term ((fractions.Fraction, Word)) – A term, as returned by
omega_terms(). The word is a tuple at every order above 1, and the string'A'at order 1.with_coeff (bool, optional) – If True, prefix the commutator with its coefficient. Default: True.
- Returns:
For example,
'+1/12 [Om_1, [Om_1, A]]'.- Return type:
Examples
import magnus.expansionterms as et [et.format_term(t) for t in et.omega_terms(3)]
['-1/2 [Om_2, A]', '+1/12 [Om_1, [Om_1, A]]']
- magnus.expansionterms.print_magnus_terms(max_order: int, file=None) None[source]
Prints the Magnus expansion, order by order, up to
max_order.Each order opens with a header naming it and counting its terms, then prints the integrand of \(\Omega_n\), one term per line, with its exact rational coefficient. Order 1 is the exception: its single term has coefficient 1 and is printed as
int A, without one.Added in version 1.0.0.
- Parameters:
- Return type:
None
Examples
import magnus.expansionterms as et et.print_magnus_terms(4)
Omega_1 (1 term) int A Omega_2 (1 term) int -1/2 [Om_1, A] Omega_3 (2 terms) int -1/2 [Om_2, A] int +1/12 [Om_1, [Om_1, A]] Omega_4 (3 terms) int -1/2 [Om_3, A] int +1/12 [Om_1, [Om_2, A]] int +1/12 [Om_2, [Om_1, A]]