From 4687ca862b36a8281fe509adb41fcba378012a29 Mon Sep 17 00:00:00 2001 From: Michael Reed <18372368+chakravala@users.noreply.github.com> Date: Sat, 5 Aug 2023 11:06:09 -0400 Subject: [PATCH] revised TensorField implementation --- Project.toml | 2 +- README.md | 135 ++++++++++++++++++++++++++++++++++++++++---- src/TensorFields.jl | 47 ++++++++++----- 3 files changed, 157 insertions(+), 27 deletions(-) diff --git a/Project.toml b/Project.toml index 611662e..df2e78b 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "TensorFields" uuid = "86e2b4fd-d9c8-44dc-a03f-e0a387f3b4e6" authors = ["Michael Reed"] -version = "0.1.0" +version = "0.1.1" [deps] Requires = "ae029012-a4dd-5104-9daa-d747884805df" diff --git a/README.md b/README.md index 2294d01..443be4c 100644 --- a/README.md +++ b/README.md @@ -46,28 +46,141 @@ Hyperrectangle (alias for ProductSpace{V, T, 3, 3} where {V, T}) Construct `dom → fun == dom → fun.(dom)` category with `\rightarrow` to initialize an example ```julia -julia> using Grassmann, TensorFields +julia> using Grassmann, TensorFields, UnicodePlots -julia> dom = (0:0.1:2π)⊕(0:0.1:2π); +julia> dom = (2π:0.01:4π)⊕(0:0.01:2π); -julia> fun(v) = (v[1]-v[2])*cos(v[2]); +julia> fun(v) = (v[1]-v[2])*cos(v[1]*v[2]/2); julia> cat = dom → fun; # dom → fun.(dom) julia> typeof(cat) TensorField{Chain{⟨++⟩, 1, Float64, 2}, ProductSpace{⟨++⟩, Float64, 2, 2, StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}}, Float64, 2} -julia> typeof(tangent(cat)) -VectorField{Chain{⟨++⟩, 1, Float64, 2}, ProductSpace{⟨++⟩, Float64, 2, 2, StepRangeLen{Float64, TwicePrecision{Float64}, TwicePrecision{Float64}, Int64}}, Chain{⟨××⟩, 1, Float64, 2}, 2} (alias for TensorField{Chain{⟨++⟩, 1, Float64, 2}, ProductSpace{⟨++⟩, Float64, 2, 2, StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}}, Chain{⟨××⟩, 1, Float64, 2}, 2}) - julia> supertype(ans) -FiberBundle{Section{Chain{⟨++⟩, 1, Float64, 2}, Chain{⟨××⟩, 1, Float64, 2}}, 2} +FiberBundle{Section{Chain{⟨++⟩, 1, Float64, 2}, Float64}, 2} + +julia> contourplot(cat) + ┌────────────────────────────────────────┐ 500 + 7 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ ┌──┐ + │⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣀⠀⠀⠀⠀⠀⠀⠀⠤⣄⡀⠠⢤⣀⠀⠀⠀⠀⠀⠀⠠⠤⠄⠀⠀⠀⠀⠀⠀⠀│ │▄▄│ + │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⠲⣍⡓⠦⢄⣀⠀⠀⠀⠀⠉⠓⠲⢬⣙⡲⢤⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ │▄▄│ + │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠓⠦⣌⡙⠲⢤⣀⡀⠀⠀⠀⠀⠉⠉⠉⠀⠀⠀⠀⠀⠀⠀⢠⣖⠆⠀⠀│ │▄▄│ + │⠀⠀⠀⠀⠘⢿⣒⠦⢤⣀⠀⠀⠀⠀⠀⠀⠉⠙⠒⠦⢭⣓⣦⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠁⠀⠀│ │▄▄│ + │⠀⠀⠀⠀⠀⠀⠈⠓⠦⢬⣉⠓⠦⢤⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⠯⣍⣉⠓⠒⠂⠀⠀│ │▄▄│ + │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠓⠒⠮⠽⠶⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣀⣀⣀⡀⠀⠀⠈⠉⠙⠂⠀⠀│ │▄▄│ + │⠀⢐⡒⠦⢤⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⠲⠤⣄⣉⡉⠉⠓⠒⠲⠄⠀⠀│ │▄▄│ + │⠀⠀⠈⠙⠒⠦⠭⢽⣲⣤⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣀⣀⣀⣀⣀⠀⠀⠀⠀⠉⠉⠙⠒⣒⡆⠀⠀│ │▄▄│ + │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠓⠲⠤⢤⣀⣈⡉⠉⠉⠓⠒⠒⠲⠤⠭⠇⠀⠀│ │▄▄│ + │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠉⠉⢓⣒⣒⣲⣤⣬⡇⠀⠀│ │▄▄│ + │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠾⣍⣉⣉⠉⠉⠉⠉⠙⠒⠒⠒⠒⠒⠦⠬⠭⠷⠶⢶⣦⡄⠀⠀│ │▄▄│ + │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠉⠉⠓⠒⠒⠒⠒⢦⣤⣤⣤⣼⣿⣿⣯⣭⡅⠀⠀│ │▄▄│ + │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣀⣀⣀⣀⡠⠤⠤⠤⠤⣄⣀⣀⣀⣀⣀⣀⣛⣛⣒⣦⣤⣤⣤⣬⣭⣍⡁⠀⠀│ │▄▄│ + 0 │⠀⠀⠀⠀⠀⠀⠀⠀⠐⠯⢥⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣐⣶⣯⣭⣭⣭⢍⣉⣉⣉⡁⠀⠀│ └──┘ + └────────────────────────────────────────┘ -400 + ⠀6⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀13⠀ ``` -Many of these methods can automatically generalize to higher dimensional manifolds and are compatible with discrete differential geometry. +Visualizing `TensorField` reperesentations can be standardized in combination with [Makie.jl](https://github.com/MakieOrg/Makie.jl) or [UnicodePlots.jl](https://github.com/JuliaPlots/UnicodePlots.jl). ```Julia -julia> F(t) = Chain(cos(t)+t*sin(t),sin(t)-t*cos(t),t^2) +julia> using Grassmann, TensorFields, UnicodePlots -julia> typeof((0:0.01:2π) → F) <: SpaceCurve +julia> t = 0:0.01:2π → identity +TensorField{Float64, StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}, Float64, 1} + ┌────────────────────────────────────────┐ + 7 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ + │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡤⠀⠀⠀⠀│ + │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⠖⠋⠀⠀⠀⠀⠀│ + │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⡴⠋⠀⠀⠀⠀⠀⠀⠀⠀│ + │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡤⠚⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ + │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⠖⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ + │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⠴⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ + │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡤⠞⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ + │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⠖⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ + │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⠴⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ + │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡤⠞⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ + │⠀⠀⠀⠀⠀⠀⠀⠀⣠⠖⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ + │⠀⠀⠀⠀⠀⣀⡴⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ + │⠀⠀⢀⡤⠞⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ + 0 │⣠⠖⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ + └────────────────────────────────────────┘ + ⠀0⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀7⠀ + +julia> cos(3t) + im*sin(2t) +TensorField{Float64, StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}, ComplexF64, 1} + ┌────────────────────────────────────────┐ + 1 │⡴⠊⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠑⠒⠒⠤⠤⢤⣀⣀⣇⣀⡠⠤⠔⠒⠒⠊⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠑⢢│ + │⢧⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡠⠤⠔⠒⠉⠉⡏⠉⠒⠢⠤⢄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡼│ + │⠀⠙⢦⡀⠀⠀⠀⠀⢀⡠⠔⠒⠋⠁⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠈⠉⠒⠤⣀⠀⠀⠀⠀⠀⣀⡴⠋⠀│ + │⠀⠀⠀⠈⠒⣄⡤⠊⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠒⢤⣴⠊⠁⠀⠀⠀│ + │⠀⠀⢀⠔⠊⠀⠈⠑⠢⢄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⢀⡠⠔⠊⠁⠀⠑⠢⡀⠀⠀│ + │⠀⡔⠁⠀⠀⠀⠀⠀⠀⠀⠈⠒⠤⣀⡀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⣀⠤⠊⠁⠀⠀⠀⠀⠀⠀⠀⠈⢦⠀│ + │⡞⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠒⠤⣀⠀⠀⡇⠀⣀⠤⠚⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢳│ + │⡧⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⣭⠶⡷⣭⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⢼│ + │⢧⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⠤⠒⠉⠀⠀⡇⠀⠉⠒⠤⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡼│ + │⠈⠳⡄⠀⠀⠀⠀⠀⠀⠀⣀⠤⠔⠉⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠑⠒⠤⣀⠀⠀⠀⠀⠀⠀⠀⢀⠞⠁│ + │⠀⠀⠈⠲⢄⡀⢀⡠⠔⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⠢⢄⡀⠀⡠⠖⠁⠀⠀│ + │⠀⠀⠀⢀⡤⠛⠣⢄⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡠⠜⠛⠤⡀⠀⠀⠀│ + │⠀⡠⠖⠁⠀⠀⠀⠀⠀⠉⠒⠤⣀⡀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⣀⠤⠒⠊⠁⠀⠀⠀⠀⠈⠳⣄⠀│ + │⡞⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠉⠒⠢⠤⣄⣀⣇⣀⠤⠴⠒⠉⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢳│ + -1 │⠣⢄⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⠤⠤⠤⠔⠒⠒⠉⠉⡏⠉⠒⠒⠲⠤⠤⠤⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⡠⠞│ + └────────────────────────────────────────┘ + ⠀-1⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀1⠀ +``` +In the above example, a technique is demonstrated where an identity `TensorField` is constructed from an interval, resulting in `t` which can be used to parametrize functions on the complex plane. +Constructing a `TensorField` can be accomplished in various ways, +there are explicit techniques to construct a `TensorField` as well as implicit methods. +Additional packages such as `Adapode` can build on the `TensorField` concept by generating them from differential equations. +```Julia +julia> using Grassmann, TensorFields, Adapode, UnicodePlots + +julia> Lorenz(x) = Chain( + 10.0(x[2]-x[1]), + x[1]*(28.0-x[3])-x[2], + x[1]*x[2]-(8/3)*x[3]); + +julia> sol = odesolve(Lorenz,Chain(10.,10.,10.)) +TensorField{Float64, StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}, Chain{⟨×××⟩, 1, Float64, 3}, 1} + ┌────────────────────────────────────────┐ + 42.9279 │⢰⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⡄⠀⠀⠀⠀⠀⠀⠀⠀│ y1 + │⢸⢧⠀⠀⢰⡆⠀⠀⢠⢧⠀⠀⠀⠀⣿⡀⠀⠀⣀⠀⠀⢀⣄⠀⠀⠀⣷⠀⠀⠀⢸⡇⠀⠀⢸⣇⠀⠀⠀⠀│ y2 + │⢸⢸⠀⠀⢸⢳⠀⠀⢸⢸⠀⠀⠀⠀⡇⡇⠀⢰⢻⠀⠀⢸⢸⠀⠀⢸⢹⡀⠀⠀⣸⢳⠀⠀⢸⢸⠀⠀⠀⠀│ y3 + │⢸⠸⡄⠀⡏⢸⡀⠀⢸⠘⡆⠀⠀⢠⠇⢧⠀⢸⠈⡇⠀⢸⠘⡆⠀⢸⠀⡇⠀⠀⡇⢸⡀⠀⣸⠈⠀⠀⠀⠀│ + │⣼⠀⣇⠀⡇⠀⡇⠀⡼⠀⢧⠀⠀⢸⠀⢸⡀⡞⠀⢳⠀⡏⠀⢧⠀⣸⠀⢳⠀⠀⡇⠀⡇⠀⡇⠀⠀⠀⠀⠀│ + │⣿⠀⠸⣴⠃⠀⢹⡀⡇⠀⠸⡄⠀⢸⠀⠀⠧⠇⠀⠘⣦⠇⠀⠸⡄⣇⠀⠸⡄⠀⣷⠀⢹⠀⡇⠀⠀⠀⠀⠀│ + │⣿⡇⠀⠉⠀⠀⠀⠳⠃⠀⠀⢧⠀⢸⠀⠀⠀⣶⡀⠀⠀⣿⡀⠀⠙⣿⡆⠀⢳⢸⣿⡄⠈⠿⠁⠀⠀⠀⠀⠀│ + │⠏⣇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⢦⡞⠀⠀⢰⡟⣷⠀⢸⡏⣧⠀⢰⡟⣷⠀⠈⣻⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀│ + │⠀⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⣾⠁⢿⣆⣾⠁⡿⡄⣼⠃⣿⡄⢀⣿⠘⣧⠀⠀⠀⠀⠀⠀⠀⠀│ + │⣀⣿⣄⣀⣀⣀⣀⣀⣀⣠⣄⣀⣀⣀⣸⣸⣁⣀⣘⣚⣁⣀⣹⣟⣋⣀⣸⣳⣾⣃⣀⣿⣄⣀⣀⣠⣀⣀⣀⣀│ + │⠀⠳⢽⡄⠀⣯⠿⣦⠀⣞⡏⠈⢿⡄⢸⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠓⠻⣆⠀⣏⠀⠀⠀⠀│ + │⠀⠀⠀⣿⣀⡿⠀⢻⡆⣿⠀⠀⠘⣧⣼⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢻⡄⣿⠀⠀⠀⠀│ + │⠀⠀⠀⢸⣿⠇⠀⠘⣧⡏⠀⠀⠀⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣷⡇⠀⠀⠀⠀│ + │⠀⠀⠀⠀⠿⠀⠀⠀⣿⠁⠀⠀⠀⢹⡟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⠁⠀⠀⠀⠀│ + -22.4896 │⠀⠀⠀⠀⠀⠀⠀⠀⠈⠀⠀⠀⠀⢸⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠀⠀⠀⠀⠀│ + └────────────────────────────────────────┘ + ⠀0⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀7⠀ + +julia> typeof(sol) <: SpaceCurve true + +julia> speed(sol) +TensorField{Float64, StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}, Single{⟨×××⟩, 0, v, Float64}, 1} + ┌────────────────────────────────────────┐ + 300 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ + │⢀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ + │⣼⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⢳⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ + │⡏⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣤⠀⠀⠀⠀⠀⠀⠀⠀⠀│ + │⡇⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀│ + │⡇⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡏⡇⠀⠀⠀⠀⠀⠀⠀⠀│ + │⠀⢧⠀⠀⠀⠀⠀⠀⣸⡄⠀⠀⠀⢸⢸⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠀⠀⠀⠀⡇⡇⠀⠀⣾⡀⠀⠀⠀⠀│ + │⠀⢸⠀⠀⣀⠀⠀⠀⡇⡇⠀⠀⠀⡏⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⡇⠀⠀⢸⠁⡇⠀⠀⡇⡇⠀⠀⠀⠀│ + │⠀⢸⠀⠀⣿⡀⠀⠀⡇⢹⠀⠀⠀⡇⠀⡇⠀⠀⠀⠀⠀⣴⡀⠀⠀⡇⢳⠀⠀⢸⠀⢳⠀⠀⡇⢧⠀⠀⠀⠀│ + │⠀⢸⠀⢠⠇⣇⠀⠀⡇⢸⠀⠀⠀⡇⠀⡇⠀⡴⡄⠀⠀⡇⢧⠀⠀⡇⢸⠀⠀⢸⠀⢸⠀⢠⠇⢸⠀⠀⠀⠀│ + │⠀⠘⡆⢸⠀⢸⠀⢸⠁⠘⡆⠀⠀⡇⠀⣇⠀⡇⢳⠀⢀⡇⢸⡀⢀⡇⠈⡇⠀⢸⠀⢸⠀⢸⠀⠘⠀⠀⠀⠀│ + │⠀⠀⡇⣸⠀⠘⡆⢸⠀⠀⣇⠀⢰⠃⠀⢸⢠⠇⠈⡇⢸⠀⠀⡇⢸⠀⠀⢧⠀⡏⠀⠈⡇⢸⠀⠀⠀⠀⠀⠀│ + │⠀⠀⠹⠇⠀⠀⢳⡞⠀⠀⠸⡄⢸⠀⠀⠘⡾⠀⠀⠹⠞⠀⠀⠹⠼⠀⠀⠘⣆⡇⠀⠀⢳⡏⠀⠀⠀⠀⠀⠀│ + │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ + 0 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ + └────────────────────────────────────────┘ + ⠀0⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀7⠀ ``` -Visualizing `TensorField` reperesentations can be standardized in combination with packages such as [Makie.jl](https://github.com/MakieOrg/Makie.jl) or [UnicodePlots.jl](https://github.com/JuliaPlots/UnicodePlots.jl). +Many of these methods can automatically generalize to higher dimensional manifolds and are compatible with discrete differential geometry. diff --git a/src/TensorFields.jl b/src/TensorFields.jl index 3d915a1..3aa6786 100644 --- a/src/TensorFields.jl +++ b/src/TensorFields.jl @@ -96,7 +96,7 @@ Base.:/(a::Section,b::Number) = base(a) ↦ (fiber(a)/b) Base.:-(s::Section) = base(s) ↦ -(fiber(s)) Base.:!(s::Section) = base(s) ↦ !(fiber(s)) Base.:~(s::Section) = base(s) ↦ ~(fiber(s)) -for fun ∈ (:inv,:exp,:log,:abs,:sqrt,:real,:imag,:cos,:sin,:tan,:cot,:sec,:csc,:asec,:acsc,:sech,:csch,:asech,:tanh,:coth,:asinh,:acosh,:atanh,:acoth,:asin,:acos,:atan,:acot,:sinc,:cosc,:abs2,:conj) +for fun ∈ (:inv,:exp,:log,:sinh,:cosh,:abs,:sqrt,:real,:imag,:cos,:sin,:tan,:cot,:sec,:csc,:asec,:acsc,:sech,:csch,:asech,:tanh,:coth,:asinh,:acosh,:atanh,:acoth,:asin,:acos,:atan,:acot,:sinc,:cosc,:abs2,:conj) @eval Base.$fun(s::Section) = base(s) ↦ $fun(fiber(s)) end Grassmann.reverse(s::Section) = base(s) ↦ reverse(fiber(s)) @@ -160,7 +160,7 @@ basetype(::TensorField{B}) where B = B fibertype(::TensorField{B,T,F} where {B,T}) where F = F Base.size(m::TensorField) = size(m.cod) -Base.resize!(m::TensorField,i) = (resize!(domain(m),i),resize(codomain(m),i)) +Base.resize!(m::TensorField,i) = (resize!(domain(m),i),resize!(codomain(m),i)) @pure Base.eltype(::Type{TensorField{B,T,F}}) where {B,T,F} = Section{B,F} Base.broadcast(f,t::TensorField) = domain(t) → f.(codomain(t)) Base.getindex(m::TensorField,i::Vararg{Int}) = getindex(domain(m),i...) ↦ getindex(codomain(m),i...) @@ -173,6 +173,23 @@ function Base.setindex!(m::TensorField{B,<:Vector{B}},s::Section,i::Vararg{Int}) return s end +Base.BroadcastStyle(::Type{<:TensorField{B,T,F} where {B,T}}) where F = Broadcast.ArrayStyle{TensorField{F}}() + +function Base.similar(bc::Broadcast.Broadcasted{Broadcast.ArrayStyle{TensorField{F}}}, ::Type{ElType}) where {F,ElType} + # Scan the inputs for the ArrayAndChar: + t = find_tf(bc) + # Use the char field of A to create the output + domain(t) → similar(Array{F}, axes(bc)) +end + +"`A = find_tf(As)` returns the first TensorField among the arguments." +find_tf(bc::Base.Broadcast.Broadcasted) = find_tf(bc.args) +find_tf(args::Tuple) = find_tf(find_tf(args[1]), Base.tail(args)) +find_tf(x) = x +find_tf(::Tuple{}) = nothing +find_tf(a::TensorField, rest) = a +find_tf(::Any, rest) = find_tf(rest) + function (m::IntervalMap{Float64,Vector{Float64}})(t) i = searchsortedfirst(domain(m),t)-1 m.cod[i]+(t-m.dom[i])/(m.dom[i+1]-m.dom[i])*(m.cod[i+1]-m.cod[i]) @@ -200,22 +217,22 @@ Base.:+(n::Number,t::TensorField) = domain(t) → (n.+codomain(t)) Base.:+(t::TensorField,n::Number) = domain(t) → (codomain(t).+n) Base.:-(n::Number,t::TensorField) = domain(t) → (n.-codomain(t)) Base.:-(t::TensorField,n::Number) = domain(t) → (codomain(t).-n) -Base.:*(a::TensorField,b::TensorField) = checkdomain(a,b) && TensorField(domain(t),codomain(a).*codomain(b)) -Base.:/(a::TensorField,t::TensorField) = checkdomain(a,b) && TensorField(domain(t),codomain(a)./codomain(b)) -Base.:+(a::TensorField,b::TensorField) = checkdomain(a,b) && TensorField(domain(t),codomain(a).+codomain(b)) -Base.:-(a::TensorField,b::TensorField) = checkdomain(a,b) && TensorField(domain(t),codomain(a).-codomain(b)) -Base.:>(a::TensorField,b::TensorField) = checkdomain(a,b) && TensorField(domain(t),codomain(a).>codomain(b)) -Base.:<(a::TensorField,b::TensorField) = checkdomain(a,b) && TensorField(domain(t),codomain(a).>(a::TensorField,b::TensorField) = checkdomain(a,b) && TensorField(domain(t),codomain(a).>>codomain(b)) -Base.:<<(a::TensorField,b::TensorField) = checkdomain(a,b) && TensorField(domain(t),codomain(a).<(a::TensorField,b::TensorField) = checkdomain(a,b) && TensorField(domain(a),codomain(a).>codomain(b)) +Base.:<(a::TensorField,b::TensorField) = checkdomain(a,b) && TensorField(domain(a),codomain(a).>(a::TensorField,b::TensorField) = checkdomain(a,b) && TensorField(domain(a),codomain(a).>>codomain(b)) +Base.:<<(a::TensorField,b::TensorField) = checkdomain(a,b) && TensorField(domain(a),codomain(a).<