Skip to content
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
7853dcb
comentario
May 17, 2023
aaf5940
Merge branch 'main' into Energy_Preserving
Sondar74 May 21, 2023
afe7373
Merge branch 'main' of github.com:Sondar74/BSeries.jl into main
Sondar74 Jun 26, 2023
e4d79cc
updated 'main' branch and created new branch 'csrkupdated'. This one …
Sondar74 Jun 26, 2023
823684d
deleted extra file
Sondar74 Jun 26, 2023
0df736b
fixing 'Spell Check'
Sondar74 Jun 26, 2023
09d4629
added docstrings and removed elementary_differentials_csrk from export
Sondar74 Jun 27, 2023
335265f
modified the comments in the functions 'PolynomialA' and 'elementary_…
Sondar74 Jun 27, 2023
8c4e0b1
Modified the function 'bseries' for CSRK
Sondar74 Jun 27, 2023
7ad5325
exported 'ContinuousStageRungeKuttaMethod'
Sondar74 Jun 27, 2023
5d82c87
added one test, and modified the function 'bseries' for CSRK
Sondar74 Jun 27, 2023
c0a724d
Spell Check
Sondar74 Jun 27, 2023
c45de1c
Update src/BSeries.jl
Sondar74 Jun 28, 2023
6616b9c
Update src/BSeries.jl
Sondar74 Jun 28, 2023
1227e1a
Update src/BSeries.jl
Sondar74 Jun 28, 2023
3691f69
Update src/BSeries.jl
Sondar74 Jun 28, 2023
68cecb0
Update test/runtests.jl
Sondar74 Jun 28, 2023
5d30865
updating docstring
Sondar74 Jun 28, 2023
7387ffc
Merge branch 'csrkupdated' of github.com:Sondar74/BSeries.jl into csr…
Sondar74 Jun 28, 2023
53fd493
fixed the values of bseries()
Sondar74 Jun 28, 2023
d6a23d6
added test for floating-point and symbolic coefficientes using SymPy …
Sondar74 Jun 28, 2023
c0ba86f
added test for Symbolics.jl: same as SymEngine
Sondar74 Jun 28, 2023
b5813d2
Update test/runtests.jl
Sondar74 Jun 28, 2023
691507f
Update test/runtests.jl
Sondar74 Jun 28, 2023
02acff4
Update test/runtests.jl
Sondar74 Jun 28, 2023
fd1a23e
added Energy_Preserving test
Sondar74 Jun 28, 2023
0c29499
Merge branch 'csrkupdated' of github.com:Sondar74/BSeries.jl into csr…
Sondar74 Jun 28, 2023
c8113e6
fixed the funtion bseries(csrk, order)
Sondar74 Jul 10, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
175 changes: 174 additions & 1 deletion src/BSeries.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ end

using Latexify: Latexify, LaTeXString
using Combinatorics: Combinatorics, permutations
using LinearAlgebra: LinearAlgebra, rank
using LinearAlgebra: LinearAlgebra, rank, dot
using SparseArrays: SparseArrays, sparse
using SymPy

@reexport using Polynomials: Polynomials, Polynomial

Expand All @@ -40,6 +41,8 @@ export renormalize!

export is_energy_preserving, energy_preserving_order

export ContinuousStageRungeKuttaMethod

# Types used for traits
# These traits may decide between different algorithms based on the
# corresponding complexity etc.
Expand Down Expand Up @@ -74,6 +77,7 @@ end

TruncatedBSeries{T, V}() where {T, V} = TruncatedBSeries{T, V}(OrderedDict{T, V}())


# general interface methods of `AbstractDict` for `TruncatedBSeries`
@inline Base.iterate(series::TruncatedBSeries) = iterate(series.coef)
@inline Base.iterate(series::TruncatedBSeries, state) = iterate(series.coef, state)
Expand Down Expand Up @@ -612,6 +616,93 @@ function bseries(ros::RosenbrockMethod, order)
return series
end

"""
ContinuousStageRungeKuttaMethod

A struct that describes a CSRK method. This kind of 'struct' should be constructed
via [`CSRK`]
'csrk = CSRK(M)'
in order to later call the 'bseries' function.

# References
- Yuto Miyatake and John C. Butcher.
"A characterization of energy-preserving methods and the construction of
parallel integrators for Hamiltonian systems."
SIAM Journal on Numerical Analysis 54, no. 3 (2016):
[DOI: 10.1137/15M1020861](https://doi.org/10.1137/15M1020861)
Comment thread
Sondar74 marked this conversation as resolved.
Outdated
Comment thread
Sondar74 marked this conversation as resolved.
Outdated
"""
Comment thread
Sondar74 marked this conversation as resolved.
struct ContinuousStageRungeKuttaMethod{MatT <: AbstractMatrix}
matrix::MatT
end


"""
bseries(csrk::ContinuousStageRungeKuttaMethod, order)

Comment thread
Sondar74 marked this conversation as resolved.
Compute the B-series of the [`ContinuousStageRungeKuttaMethod`](@ref) `csrk`
up to the prescribed integer `order` as described by Miyatake & Butcher (2015).

!!! note "Normalization by elementary differentials"
The coefficients of the B-series returned by this method need to be
multiplied by a power of the time step divided by the `symmetry` of the
rooted tree and multiplied by the corresponding elementary differential
of the input vector field ``f``.
See also [`evaluate`](@ref).
Comment thread
Sondar74 marked this conversation as resolved.
Outdated

# Example:
The energy-preserving 4x4 matrix given by Miyatake & Butcher (2015) is
```
M = [-6//5 72//5 -36//1 24//1;
72//5 -144//5 -48//1 72//1;
-36//1 -48//1 720//1 -720//1;
24//1 72//1 -720//1 720//1]
```

Then, we calculate the bseries with the following code:
Comment thread
Sondar74 marked this conversation as resolved.
Outdated

```
csrk = CSRK(M)
series = bseries(csrk, 4)
TruncatedBSeries{RootedTree{Int64, Vector{Int64}}, Rational{Int64}} with 9 entries:
RootedTree{Int64}: Int64[] => 1//1
RootedTree{Int64}: [1] => 1//1
RootedTree{Int64}: [1, 2] => 1//2
RootedTree{Int64}: [1, 2, 3] => 6004799503160661//36028797018963968
RootedTree{Int64}: [1, 2, 2] => 6004799503160661//18014398509481984
RootedTree{Int64}: [1, 2, 3, 4] => 6004799503160661//144115188075855872
RootedTree{Int64}: [1, 2, 3, 3] => 6004799503160661//72057594037927936

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Is this really correct?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

No, sorry: seems like there is something happening with the definition of V in

series = TruncatedBSeries{RootedTree{Int, Vector{Int}}, V}()
series[rootedtree(Int[])] = one(V)

so that, although the output of elementary_differentials_csrk(csrk, t) is correct, for some values it will throw an approximation to the original result instead of saving the value of elementary_differentials_csrk(csrk, t) Do you know how can I fix it?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Seems like the numerical function N() solves this issue, but I don't know if it has limitations for future applications of this code (since this is the first time I'm working with this function).

@ranocha ranocha Jun 28, 2023

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Let's see. First, please add more tests etc. - and fix the CI problems. Then, possible problem can show up already

RootedTree{Int64}: [1, 2, 3, 2] => 1//8
RootedTree{Int64}: [1, 2, 2, 2] => 1//4

```
Comment thread
Sondar74 marked this conversation as resolved.
# References
- Yuto Miyatake and John C. Butcher.
"A characterization of energy-preserving methods and the construction of
parallel integrators for Hamiltonian systems."
SIAM Journal on Numerical Analysis 54, no. 3 (2016):
[DOI: 10.1137/15M1020861](https://doi.org/10.1137/15M1020861)
Comment thread
Sondar74 marked this conversation as resolved.
Outdated
"""
function bseries(csrk::ContinuousStageRungeKuttaMethod, order)
Comment thread
Sondar74 marked this conversation as resolved.
csrk = csrk.matrix
V_tmp = eltype(csrk)
if V_tmp <: Integer
# If people use integer coefficients, they will likely want to have results
# as exact as possible. However, general terms are not integers. Thus, we
# use rationals instead.
V = Rational{V_tmp}
else
V = V_tmp
end
series = TruncatedBSeries{RootedTree{Int, Vector{Int}}, V}()
series[rootedtree(Int[])] = one(V)
for o in 1:order
for t in RootedTreeIterator(o)
series[copy(t)] = elementary_differentials_csrk(csrk, t)
end
end
return series
end
Comment on lines +675 to +707

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Please add tests. This does not work correctly right now.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Okey, I'm working on this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

When working with the function one(), I have the problem that eltype(csrk) returns Any. How can I fix it?

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

What is the csrk that you use here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It is the csrk obtained from csrk = ContinuousStageRungeKuttaMethod(M), for a matrix M.

@ranocha ranocha Jun 28, 2023

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Use eltype(csrk.matrix) instead or define eltype(csrk::ContinuousStageRungeKuttaMethod) appropriately. The latter would be my preferred option, e.g.,

struct ContinuousStageRungeKuttaMethod{T, MatT <: AbstractMatrix{T}} <: RootedTrees.AbstractTimeIntegrationMethod
    A::MatT
end

Base.eltype(::ContinuousStageRungeKuttaMethod{T}) where {T} = T


# TODO: bseries(ros::RosenbrockMethod)
# should create a lazy version, optionally a memoized one

Expand Down Expand Up @@ -2016,4 +2107,86 @@ function equivalent_trees(tree)
return equivalent_trees_set
end


# This function generates a polynomial
# A_{t,z} = [t,t^2/2,..., t^s/s]*M*[1, z, ..., z^(s-1)]^T
# for a given square matrix M of dimension s and chars 't' and 'z'.
function PolynomialA(M,t,z)
# get the dimension of the matrix
s = size(M,1)
# we need symbolic variables to work with
variable1 = Sym(t)
variable2 = Sym(z)
# conjugate the variable 1, since this will be the variable of the left polynomial
# and the function 'dot' assumes it to be conjugated
variable1 = conjugate(variable1)
# generate the components of the polynomial with powers of t
poli_z = Array{SymPy.Sym}(undef, s)
for i in 1:s
poli_z[i] = variable2^(i-1)
end
# generate the components of the polynomial with powers of z
poli_t = Array{SymPy.Sym}(undef, s)
for i in 1:s
poli_t[i] = (1 // i)*(variable1^i)
end
# multiply matrix times vector
result = M * poli_z
# use dot product for the two vectors
return dot(poli_t,result)
end


"""
elementary_differentials_csrk(M,tree)

This function calculates the CSRK elementary differential for a given
square matrix 'M' and a given RootedTree according to [@ref].

# References
Butcher, John & Miyatake, Yuto. (2015). A Characterization of Energy-Preserving
Methods and the Construction of Parallel Integrators for Hamiltonian Systems.
SIAM Journal on Numerical Analysis. 54. 10.1137/15M1020861.
(https://www.researchgate.net/publication/276211444_A_Characterization_of_Energy-Preserving_Methods_and_the_Construction_of_Parallel_Integrators_for_Hamiltonian_Systems)

"""
function elementary_differentials_csrk(M,rootedtree)
# we extract the level_sequence of 'rootedtree'
tree = rootedtree.level_sequence
m = maximum(tree)
l = length(tree)
# Since we will integrate with symbolic variables for
# every node in the tree, we create the variables called
# 'xi' for 1 <= i <= m, because m is the most distant node from the root.
variables = []
for i in 1:m
var_name = "x$i"
var = Sym(var_name)
push!(variables, var)
end
# we will calculate an integral for every node in the level_sequence from right to left
inverse_counter = l-1
# stablish initial integrand, which is the rightmost leaf (last node of the level sequence)
if l > 1
integrand = integrate(PolynomialA(M,variables[tree[end]-1],variables[tree[end]]),(variables[tree[end]],0,1))
else
# if the RootedTree is [1] or [], the elementary differential will be 1.
return 1
end
# Start a cycle for integrating
while inverse_counter > 1
# we define the pseudo_integrand as the product between the last integral and the new polynomial (since the polynomials are
# multiplying each others inside the biggest integral). For a node 'i', this new Polynomial is computed for the variables
# 'xi' and 'x(i-1)'.
pseudo_integrand = PolynomialA(M,variables[tree[inverse_counter]-1],variables[tree[inverse_counter]])*integrand
# integrate this new pseudo_integrand with respect to the variable 'xi'
integrand = integrate(pseudo_integrand,(variables[tree[inverse_counter]],0,1))
inverse_counter -= 1
end
# Once we have covered every node except for the base, multiply for the Basis_Polynomial, i.e. the Polynomial B
# defined by B_{x1} = A_{1, x1}.
# return the integral with respect to x1.
return integrate(PolynomialA(M,1,variables[1])*integrand,(variables[1],0,1))
end

end # module
37 changes: 37 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2058,4 +2058,41 @@ using Aqua: Aqua
Aqua.test_project_toml_formatting(BSeries)
end
end

@testset "Continuous Stage Runge-Kutta Method" begin
@testset "(Inverse) 4x4-Hilbert Matrix" begin
# References
# - Yuto Miyatake and John C. Butcher.
# "A characterization of energy-preserving methods and the construction of
# parallel integrators for Hamiltonian systems."
# SIAM Journal on Numerical Analysis 54, no. 3 (2016):
# [DOI: 10.1137/15M1020861](https://doi.org/10.1137/15M1020861)

# This is the matrix obtained by inverting the 4x4-Hilbert matrix
M = [-6//5 72//5 -36//1 24//1;
72//5 -144//5 -48//1 72//1;
-36//1 -48//1 720//1 -720//1;
24//1 72//1 -720//1 720//1]
csrk = ContinuousStageRungeKuttaMethod(M)
# Generate the bseries up to order 4
order = 4
series = bseries(csrk, order)
l = length(series)
# we save the expected coefficients in the following array
expected_coefficients = [1//1 ,1//1, 1//2, 6004799503160661//36028797018963968, 6004799503160661//18014398509481984, 6004799503160661//144115188075855872, 6004799503160661//72057594037927936, 1//8, 1//4]
# define a Bool 'coef_match' which checks if all the obtained coefficients are the same as the expected ones.
coef_match = true
# generate every RootedTree up to order 4, and check if its coefficient in 'series' matches the expected ones
counter = 2
for o in 1:order
for t in RootedTreeIterator(o)
if series[t] != expected_coefficients[counter]
coef_match = false
end
counter += 1
end
end
@test coef_match == true
Comment thread
Sondar74 marked this conversation as resolved.
Outdated
end
end
end # @testset "BSeries"