Yoshida
Yoshida integrator (coefficients and step)
- ndmap.yoshida.coefficients(k: int, n: int, m: int, merge: bool) list[list[int], list[float]]
Generate Yoshida coefficients multistep
Given a set of symplectic mappings indexed as 0, 1, …, (l - 1) and Yoshida n <= m orders Construct Yoshida coefficients (i1, x1), (i2, x2), …, (i2, x2), (i1, x1) f(2m)(dt) = f(i1)(x1 dx) o f(i2)(x2 dx) o … o f(i2)(x2 dx) o f(i1)(x1 dx)
- Parameters:
k (int, positive) – number of mappings
n (int, non-negative) – start Yoshida order
m (int, non-negative) – final Yoshida order
merge (bool) – flag to merge edge mappings (assume commuting)
- Return type:
list[list[int], list[float]]
Examples
>>> coefficients(1, 0, 0, True) [[0], [1.0]]
>>> coefficients(1, 1, 1, True) [[0], [1.0]]
>>> coefficients(1, 1, 1, False) [[0, 0, 0], [1.3512071919596578, -1.7024143839193153, 1.3512071919596578]]
>>> coefficients(2, 0, 0, True) [[0, 1, 0], [0.5, 1.0, 0.5]]
>>> coefficients(4, 0, 0, True) [[0, 1, 2, 3, 2, 1, 0], [0.5, 0.5, 0.5, 1.0, 0.5, 0.5, 0.5]]
>>> coefficients(2, 1, 1, True) [[0, 1, 0, 1, 0, 1, 0], [0.6756035959798289, 1.3512071919596578, -0.17560359597982877, -1.7024143839193153, -0.17560359597982877, 1.3512071919596578, 0.6756035959798289]]
>>> coefficients(2, 1, 1, False) [[0, 1, 0, 0, 1, 0, 0, 1, 0], [0.6756035959798289, 1.3512071919596578, 0.6756035959798289, -0.8512071919596577, -1.7024143839193153, -0.8512071919596577, 0.6756035959798289, 1.3512071919596578, 0.6756035959798289]]
- ndmap.yoshida.yoshida(n: int, m: int, merge: bool, mappings: list[Callable], parameters: list[list] | None = None) Callable [source]
Construct Yoshida integration multistep
- Parameters:
n (int, non-negative) – start Yoshida order
m (int, non-negative) – final Yoshida order
merge (bool) – flag to merge edge mappings (assume commuting)
mappings (list[Mapping]) – list of (time-reversible) mappings
parameters (Optional[list[list]], default=None) – list of optional fixed parameters for each mapping
- Return type:
Mapping
Examples
>>> def fn(x, t): q, p = x ; return torch.stack([q, p - t*q]) >>> def gn(x, t): q, p = x ; return torch.stack([q + t*p, p]) >>> t = torch.tensor(0.5, dtype=torch.float64) >>> x = torch.tensor([0.1, 0.1], dtype=torch.float64) >>> yoshida(1, 0, True, [fn, gn])(x, t) tensor([0.1344, 0.0375], dtype=torch.float64) >>> yoshida(1, 1, True, [fn, gn])(x, t) tensor([0.1358, 0.0402], dtype=torch.float64) >>> yoshida(1, 2, True, [fn, gn])(x, t) tensor([0.1357, 0.0398], dtype=torch.float64) >>> yoshida(1, 3, True, [fn, gn])(x, t) tensor([0.1357, 0.0398], dtype=torch.float64) >>> yoshida(1, 4, True, [fn, gn])(x, t) tensor([0.1357, 0.0398], dtype=torch.float64)
>>> def fn(x, t): q, p = x ; return torch.stack([q, p - t*q]) >>> def gn(x, t): q, p = x ; return torch.stack([q + t*p, p]) >>> def s2(x, t): ... x1, x2, x1 = 0.5, 1.0, 0.5 ... y = torch.clone(x) ... x = fn(x, x1*t) ... x = gn(x, x2*t) ... x = fn(x, x1*t) ... return x >>> def s4(x, t): ... x1, x2, x1 = coefficients(1) ... x = torch.clone(x) ... x = s2(x, x1*t) ... x = s2(x, x2*t) ... x = s2(x, x1*t) ... return x >>> def s6(x, t): ... x1, x2, x1 = coefficients(2) ... x = torch.clone(x) ... x = s4(x, x1*t) ... x = s4(x, x2*t) ... x = s4(x, x1*t) ... return x >>> t = torch.tensor(0.5, dtype=torch.float64) >>> x = torch.tensor([0.1, 0.1], dtype=torch.float64) >>> torch.allclose(s2(x, t), yoshida(0, 0, True, [fn, gn])(x, t)) True >>> torch.allclose(s4(x, t), yoshida(0, 1, True, [fn, gn])(x, t)) True >>> torch.allclose(s6(x, t), yoshida(0, 2, True, [fn, gn])(x, t)) True >>> torch.allclose(yoshida(1, 1, False, [s2])(x, t), yoshida(0, 1, True, [fn, gn])(x, t)) True >>> torch.allclose(yoshida(2, 2, False, [s4])(x, t), yoshida(0, 2, True, [fn, gn])(x, t)) True >>> torch.allclose(yoshida(3, 3, False, [s6])(x, t), yoshida(0, 3, True, [fn, gn])(x, t)) True
>>> from ndmap.derivative import derivative >>> def fn(x, t, k): q, p = x ; return torch.stack([q, p - t*k*q]) >>> def gn(x, t, k): q, p = x ; return torch.stack([q + t*p, p]) >>> t = torch.tensor(0.5, dtype=torch.float64) >>> x = torch.tensor([0.1, 0.1], dtype=torch.float64) >>> k = torch.tensor(1.0, dtype=torch.float64) >>> derivative(1, yoshida(1, 2, True, [fn, gn]), x, t, k) [tensor([0.1357, 0.0398], dtype=torch.float64), tensor([[ 0.8775, 0.4800], [-0.4792, 0.8775]], dtype=torch.float64)] >>> derivative((1, 1), yoshida(1, 2, True, [fn, gn]), x, t, k) [[tensor([0.1357, 0.0398], dtype=torch.float64), tensor([ 0.0404, -0.1356], dtype=torch.float64)], [tensor([[ 0.8775, 0.4800], [-0.4792, 0.8775]], dtype=torch.float64), tensor([[-0.4810, 0.8850], [-0.8750, -0.4810]], dtype=torch.float64)]] >>> derivative((1, 1, 1), yoshida(1, 2, True, [fn, gn]), x, t, k) [[[tensor([0.1357, 0.0398], dtype=torch.float64), tensor([-0.0139, -0.0579], dtype=torch.float64)], [tensor([ 0.0404, -0.1356], dtype=torch.float64), tensor([-0.0563, -0.1213], dtype=torch.float64)]], [[tensor([[ 0.8775, 0.4800], [-0.4792, 0.8775]], dtype=torch.float64), tensor([[-0.1202, -0.0187], [-0.4584, -0.1202]], dtype=torch.float64)], [tensor([[-0.4810, 0.8850], [-0.8750, -0.4810]], dtype=torch.float64), tensor([[-0.4654, -0.0978], [-0.7473, -0.4654]], dtype=torch.float64)]]]
>>> from ndmap.propagate import identity >>> from ndmap.propagate import propagate >>> from ndmap.derivative import derivative >>> def fn(x, t, k): q, p = x ; return torch.stack([q, p - t*k*q]) >>> def gn(x, t, k): q, p = x ; return torch.stack([q + t*p, p]) >>> t = torch.tensor(0.5, dtype=torch.float64) >>> x = torch.tensor([0.1, 0.1], dtype=torch.float64) >>> k = torch.tensor(1.0, dtype=torch.float64) >>> propagate((2, ), (1, ), identity((1, ), [x]), [], yoshida(1, 2, True, [fn, gn]), t, k) [tensor([0.1357, 0.0398], dtype=torch.float64), tensor([[ 0.8775, 0.4800], [-0.4792, 0.8775]], dtype=torch.float64)]
Note
Each signature mapping in mappings is (state, delta, *args) Fixed parameters are passed at the end Coefficients are attached to the output (table attribute)