Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cubic Hermite interpolation #5

Merged
merged 14 commits into from
Sep 23, 2024
11 changes: 11 additions & 0 deletions .JuliaFormatter.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
short_to_long_function_def = true
always_for_in = true
whitespace_ops_in_indices = true
pipe_to_function_call = true
import_to_using = true
always_use_return = true
whitespace_in_kwargs = false
remove_extra_newlines = true
annotate_untyped_fields_with_any = false
conditional_to_if = false
ignore = ["tutorials"]
2 changes: 1 addition & 1 deletion .github/workflows/documenter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
- uses: actions/checkout@v4
- uses: quarto-dev/quarto-actions/setup@v2
with:
version: "1.3.353"
version: "1.5.56"
- uses: julia-actions/setup-julia@latest
with:
version: "1.10"
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
docs/Manifest.toml
examples/Manifest.toml
examples/.CondaPkg/
examples/_freeze/
docs/.CondaPkg
5 changes: 5 additions & 0 deletions CondaPkg.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[deps]
jupyter = ""
python = "3.11"
matplotlib = ">=3.4"
matplotlib-inline = ""
7 changes: 7 additions & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ version = "0.1.0"

[extras]
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
ManifoldDiff = "af67fdf4-a580-4b9f-bbec-742ef357defd"
Manifolds = "1cead3c2-87b3-11e9-0ccd-23c62b72b94e"

[compat]
ManifoldDiff = "0.3"
Manifolds = "0.10"
julia = "1.6"

[targets]
test = ["Test"]
7 changes: 7 additions & 0 deletions docs/Project.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
[deps]
CondaPkg = "992eb4ea-22a4-4c89-a5bb-47a3300528ab"
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
DocumenterCitations = "daee34ce-89f3-4625-b898-19384cb65244"
DocumenterInterLinks = "d12716ef-a0f6-4df4-a9f1-a5a34e75c656"
ManifoldDiff = "af67fdf4-a580-4b9f-bbec-742ef357defd"
ManifoldExamples = "21be47e3-92bf-4199-8515-27870869dcc6"
Manifolds = "1cead3c2-87b3-11e9-0ccd-23c62b72b94e"
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"

[compat]
CondaPkg = "0.2"
Documenter = "1"
DocumenterCitations = "1"
DocumenterInterLinks = "0.3"
Plots = "1"
15 changes: 15 additions & 0 deletions docs/build/references.bib
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@

@article{Zimmermann:2020,
title = {Hermite {Interpolation} and {Data} {Processing} {Errors} on {Riemannian} {Matrix} {Manifolds}},
volume = {42},
issn = {1064-8275},
url = {https://epubs.siam.org/doi/10.1137/19M1282878},
doi = {10.1137/19M1282878},
number = {5},
journal = {SIAM Journal on Scientific Computing},
author = {Zimmermann, Ralf},
month = jan,
year = {2020},
note = {Publisher: Society for Industrial and Applied Mathematics},
pages = {A2593--A2619},
}
39 changes: 36 additions & 3 deletions docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,29 @@
#
#

if "--help" ∈ ARGS
println(
"""
docs/make.jl

Render the `Manopt.jl` documentation with optional arguments

Arguments
* `--help` - print this help and exit without rendering the documentation
* `--prettyurls` – toggle the prettyurls part to true (which is otherwise only true on CI)
* `--quarto` – run the Quarto notebooks from the `tutorials/` folder before generating the documentation
this has to be run locally at least once for the `tutorials/*.md` files to exist that are included in
the documentation (see `--exclude-examples`) for the alternative.
If they are generated once they are cached accordingly.
Then you can spare time in the rendering by not passing this argument.
If quarto is not run, some tutorials are generated as empty files, since they
are referenced from within the documentation. These are currently
`Optimize.md` and `ImplementOwnManifold.md`.
""",
)
exit(0)
end

#
# (a) if docs is not the current active environment, switch to it
# (from https://github.com/JuliaIO/HDF5.jl/pull/1020/) 
Expand All @@ -13,24 +36,28 @@ if Base.active_project() != joinpath(@__DIR__, "Project.toml")
Pkg.instantiate()
end

# (b) Did someone say render? Then we render!
# (b) Did someone say render?
if "--quarto" ∈ ARGS
using CondaPkg
CondaPkg.withenv() do
@info "Rendering Quarto"
examples_folder = (@__DIR__) * "/../examples"
# instantiate the tutorials environment if necessary
Pkg.activate(examples_folder)
# For a breaking release -> also set the tutorials folder to the most recent version
Pkg.develop(PackageSpec(; path=(@__DIR__) * "/../"))
Pkg.resolve()
Pkg.instantiate()
Pkg.build("IJulia") # build IJulia to the right version.
Pkg.build("IJulia") # build `IJulia` to the right version.
Pkg.activate(@__DIR__) # but return to the docs one before
run(`quarto render $(examples_folder)`)
return run(`quarto render $(examples_folder)`)
end
end

# (c) load necessary packages for the docs
using Documenter: DocMeta, HTML, MathJax3, deploydocs, makedocs
using DocumenterCitations

using ManifoldExamples

generated_path = joinpath(@__DIR__, "src")
Expand All @@ -52,13 +79,19 @@ open(joinpath(generated_path, "contributing.md"), "w") do io
end
end

examples_menu = "Examples" => ["Cubic Hermite interpolation" => "examples/hermite.md"]

bib = CitationBibliography(joinpath(@__DIR__, "src", "references.bib"); style=:alpha)
makedocs(;
format=HTML(; mathengine=MathJax3(), prettyurls=get(ENV, "CI", nothing) == "true"),
sitename="ManifoldExamples.jl",
modules=[ManifoldExamples],
pages=[
"Home" => "index.md",
examples_menu,
"Contributing to ManifoldExamples.jl" => "contributing.md",
"References" => "references.md",
],
plugins=[bib],
)
deploydocs(; repo="github.com/JuliaManifolds/ManifoldExamples.jl", push_preview=true)
File renamed without changes.
15 changes: 15 additions & 0 deletions docs/src/references.bib
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@

@article{Zimmermann:2020,
title = {Hermite {Interpolation} and {Data} {Processing} {Errors} on {Riemannian} {Matrix} {Manifolds}},
volume = {42},
issn = {1064-8275},
url = {https://epubs.siam.org/doi/10.1137/19M1282878},
doi = {10.1137/19M1282878},
number = {5},
journal = {SIAM Journal on Scientific Computing},
author = {Zimmermann, Ralf},
month = jan,
year = {2020},
note = {Publisher: Society for Industrial and Applied Mathematics},
pages = {A2593--A2619},
}
4 changes: 4 additions & 0 deletions docs/src/references.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Literature

```@bibliography
```
1 change: 1 addition & 0 deletions examples/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/.quarto/
11 changes: 11 additions & 0 deletions examples/Project.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,13 @@
[deps]
IJulia = "7073ff75-c697-5162-941a-fcdaad2a7d2a"
ManifoldDiff = "af67fdf4-a580-4b9f-bbec-742ef357defd"
ManifoldExamples = "21be47e3-92bf-4199-8515-27870869dcc6"
Manifolds = "1cead3c2-87b3-11e9-0ccd-23c62b72b94e"
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
PythonPlot = "274fc56d-3b97-40fa-a1cd-1b4a50311bf9"
RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd"

[compat]
IJulia = "1"
Plots = "1"
PythonPlot = "1"
4 changes: 2 additions & 2 deletions examples/_quarto.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ execute:

format:
commonmark:
variant: -raw_html+tex_math_dollars
variant: -raw_html+tex_math_dollars+pipe_tables+footnotes
wrap: preserve

jupyter: "julia-1.10"
jupyter: julia-1.10
115 changes: 115 additions & 0 deletions examples/hermite.qmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
---
title: "Cubic Hermite interpolation on manifolds"
author: "Mateusz Baran"
date: 05/09/2024
---

## Introduction

This example shows how to perform cubic Hermite interpolation on Riemannian manifolds. The idea is described in [Zimmermann:2020](@cite).

First, let's import necessary libraries.

```{julia}
using Manifolds, ManifoldDiff, Plots
using ManifoldDiff: differential_log_argument
pythonplot()

```

The main interpolation function directly follows Eq (2.5) from [Zimmermann:2020](@cite).

```{julia}

function manifold_hermite_interpolation(
M::AbstractManifold,
p,
q,
Xp,
Xq,
t::Real,
)
Y_qp = log(M, q, p)
Xp_to_q = differential_log_argument(M, q, p, Xp)
a0t = 2*t^3 - 3*t^2 + 1 # simplified (A.1)
b0t = t^3 - 2*t^2 + t # simplified (A.3)
b1t = t^3 - t^2 # simplified (A.4)
return exp(M, q, a0t .* Y_qp .+ b0t .* Xp_to_q .+ b1t .* Xq)
end
```

We can now plot the interpolating line between two points on a sphere ($p$ and $q$) with tangent vectors $X_p$ and $X_q$. The curve $c\colon [0, 1] \to \mathbb{S}^2$ defined by `manifold_hermite_interpolation` now has the following interpolation properties:

1. $c(0) = p$
2. $c(1) = q$
3. $\dot{c}(0) = X_p$
4. $\dot{c}(1) = X_q$
5. In the Euclidean case, the `manifold_hermite_interpolation` conicides with cubic Hermite interpolation.

```{julia}

M = Sphere(2)
p = [0.8266841314682074, 0.3288540904434144, 0.45656142410117206]
Xp = [0.15493539779687937, 0.5824002702016382, -0.7000314284584177]

q = [0.0, 1.0, 0.0]
Xq = [-2, 0.0, 5]

scene = plot(M, [p, q]; wireframe_color=colorant"#CCCCCC", markersize=10, camera=(140.0, 10.0))
plot!(scene, M, [p, q], [Xp, Xq]; wireframe = false, linewidth=1.5)

interp_line = [manifold_hermite_interpolation(M, p, q, Xp, Xq, t) for t in 0.0:0.01:1.0]
plot!(scene, M, interp_line; wireframe = false, linewidth=1.5)

```

Now, let's add interpolating curve with reversed start and end, and reflected tangent vectors.
Note that for, contrary to the Eulidean case, the order of points does matter for cubic interpolation on a sphere.

```{julia}

scene = plot(M, [p, q]; wireframe_color=colorant"#CCCCCC", markersize=10, camera=(140.0, 10.0))
plot!(scene, M, [p, q], [Xp, Xq]; wireframe = false, linewidth=1.5)

plot!(scene, M, interp_line; wireframe = false, linewidth=1.5)
interp_line2 = [manifold_hermite_interpolation(M, q, p, -Xq, -Xp, t) for t in 0.0:0.01:1.0]
plot!(scene, M, interp_line2; wireframe = false, linewidth=1.5)

```

One possible way of making an interpolation method that is independent of the order of points in computing the average between these two interplations (see `manifold_hermite_interpolation_symmetric` below).


```{julia}

function manifold_hermite_interpolation_symmetric(
M::AbstractManifold,
p,
q,
Xp,
Xq,
t::Real,
)
r_pq = manifold_hermite_interpolation(M, p, q, Xp, Xq, t)
r_qp = manifold_hermite_interpolation(M, q, p, -Xq, -Xp, 1-t)
return mid_point(M, r_pq, r_qp)
end
scene = plot(M, [p, q]; wireframe_color=colorant"#CCCCCC", markersize=10, camera=(140.0, 10.0))
plot!(scene, M, [p, q], [Xp, Xq]; wireframe = false, linewidth=1.5)

plot!(scene, M, interp_line; wireframe = false, linewidth=1.5)
plot!(scene, M, interp_line2; wireframe = false, linewidth=1.5)

interp_line3 = [manifold_hermite_interpolation_symmetric(M, q, p, -Xq, -Xp, t) for t in 0.0:0.01:1.0]
plot!(scene, M, interp_line3; wireframe = false, linewidth=1.5)

```

## Literature

````{=commonmark}
```@bibliography
Pages = ["hermite.md"]
Canonical=false
```
````
4 changes: 1 addition & 3 deletions test/runtests.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
using ManifoldExamples, Test

@testset "Manifold Examples" begin

end
@testset "Manifold Examples" begin end
Loading