Repository: JuliaManifolds/ManifoldsBase.jl
Pull request #75 (2021-06-08 15:02:03)

Introduce different decorator types
This PR is WIP to introduce a nicer (shorter) way of introducing decorators.
The `AbstractDecoratorType` is a supertype of the embedding type we already have, on the abstract level of the decorator manifold and is meant to work similarly.

This should currently already work, is backward compatible for everything “below” the AbstractDecoratorManifold, while this type itself got a second parameter (so in general that should also still work, I hope).

For example the new `DefaultMetricDecorator` can be used for completely new features, i.e. when a decorator introduces functions but does not affect old ones. 

* [x] introduce the new type and clean up the two existing decorators to have less dispatch rules defined.
* [x] check for easy entrance types to also provide, i.e. something like `DefaultMetricDecorator` which acts transparent unless the metric is involved, and ideas like that.
* [x] update documentation
* [x] if we have a good idea how to restyle the decorator approach, i.e. internal optimization, that would also be good

codecov[bot]: # [Codecov](https://codecov.io/gh/JuliaManifolds/ManifoldsBase.jl/pull/75?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=JuliaManifolds) Report
> Merging [#75](https://codecov.io/gh/JuliaManifolds/ManifoldsBase.jl/pull/75?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=JuliaManifolds) (39a9eeb) into [master](https://codecov.io/gh/JuliaManifolds/ManifoldsBase.jl/commit/50b214635efc864a4dd0076c0e4e69b6b5d828ab?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=JuliaManifolds) (50b2146) will **decrease** coverage by `0.00%`.
> The diff coverage is `100.00%`.

> :exclamation: Current head 39a9eeb differs from pull request most recent head 0fea37e. Consider uploading reports for the commit 0fea37e to get more accurate results
[![Impacted file tree graph](https://codecov.io/gh/JuliaManifolds/ManifoldsBase.jl/pull/75/graphs/tree.svg?width=650&height=150&src=pr&token=bQsBUU9knE&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=JuliaManifolds)](https://codecov.io/gh/JuliaManifolds/ManifoldsBase.jl/pull/75?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=JuliaManifolds)

```diff
@@            Coverage Diff             @@
##           master      #75      +/-   ##
==========================================
- Coverage   99.85%   99.85%   -0.01%     
==========================================
  Files          14       14              
  Lines        1426     1391      -35     
==========================================
- Hits         1424     1389      -35     
  Misses          2        2              
```


| [Impacted Files](https://codecov.io/gh/JuliaManifolds/ManifoldsBase.jl/pull/75?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=JuliaManifolds) | Coverage Δ | |
|---|---|---|
| [src/ManifoldsBase.jl](https://codecov.io/gh/JuliaManifolds/ManifoldsBase.jl/pull/75/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=JuliaManifolds#diff-c3JjL01hbmlmb2xkc0Jhc2Uuamw=) | `99.07% <ø> (-0.01%)` | :arrow_down: |
| [src/ValidationManifold.jl](https://codecov.io/gh/JuliaManifolds/ManifoldsBase.jl/pull/75/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=JuliaManifolds#diff-c3JjL1ZhbGlkYXRpb25NYW5pZm9sZC5qbA==) | `100.00% <ø> (ø)` | |
| [src/bases.jl](https://codecov.io/gh/JuliaManifolds/ManifoldsBase.jl/pull/75/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=JuliaManifolds#diff-c3JjL2Jhc2VzLmps) | `100.00% <ø> (ø)` | |
| [src/DecoratorManifold.jl](https://codecov.io/gh/JuliaManifolds/ManifoldsBase.jl/pull/75/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=JuliaManifolds#diff-c3JjL0RlY29yYXRvck1hbmlmb2xkLmps) | `100.00% <100.00%> (ø)` | |
| [src/EmbeddedManifold.jl](https://codecov.io/gh/JuliaManifolds/ManifoldsBase.jl/pull/75/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=JuliaManifolds#diff-c3JjL0VtYmVkZGVkTWFuaWZvbGQuamw=) | `99.18% <100.00%> (-0.12%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/JuliaManifolds/ManifoldsBase.jl/pull/75?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=JuliaManifolds).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=JuliaManifolds)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/JuliaManifolds/ManifoldsBase.jl/pull/75?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=JuliaManifolds). Last update [50b2146...0fea37e](https://codecov.io/gh/JuliaManifolds/ManifoldsBase.jl/pull/75?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=JuliaManifolds). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=JuliaManifolds).

kellertuer: We till have to check whether we can introduce some nice type here.
What I did for now

1. There is now a(n abstract) transparency type on the decorator level. The old EmbeddingManifold transparency inherits from this.
2. There is a default transparency type which is just
  * `:parent` for all non-mutating functions (so they go to the parent, allocate and call the mutating one) – explicitly set
  * `:transparent` for all mutating functions (by default definition)
3. s´this already sparsified what we have to define on the `EmbeddedManifold` side.
4. I would like to not define `MetricTransparencyType` nor `GroupTransparencyType`, since both are not for types defined here but over on manifolds
5. I optimised codelength
6. unified how along/direction/to vector transports are handled – just have to adapt tests, too.

Where could we improve documentation? I do not think we can do that much here, but it has to be done over on Manifolds.jl, then.
kellertuer: This should be ok now; note that it is breaking, since the `AbstractDecoratorManifold` has now a new parameter.
kellertuer: Ah, one just has to add the type to the MetricManifold super type (maybe introduce a `MetricTransparencyType` and import the abstract type accordingly. For Group Manifold the Embedded Manifold just does the job, but we should refine that then.
mateuszbaran: I still don't quite understand why certain functions are in certain lists but at least it looks much cleaner now :slightly_smiling_face: . It would be great it this could be used to clean up metric and group manifolds a little.

> Ah, one just has to add the type to the MetricManifold super type (maybe introduce a `MetricTransparencyType` and import the abstract type accordingly. For Group Manifold the Embedded Manifold just does the job, but we should refine that then.

Metric transparency has some weird interactions with connected manifolds. Connected manifolds should override the entire metric structure though it still might make sense to have a norm on tangent spaces (but not the inner product). So the connected manifold should invalidate `inner` but not necessarily `norm` -- though I don't know how useful it could be.
kellertuer: > It would be great it this could be used to clean up metric and group manifolds a little.

The MetricManifold needs a little update anyways, and the group manifold will get its own transparency type I think and then I will rework, that anyways.
While it is breaking here, it should be nonbreaking for them, though.

> Metric transparency has some weird interactions with connected manifolds. Connected manifolds should override the entire metric structure though it still might make sense to have a norm on tangent spaces (but not the inner product). So the connected manifold should invalidate `inner` but not necessarily `norm` -- though I don't know how useful it could be.

Do you mean `ConnectionManifold`? Sure, since both metric and connection are a similar way to provide the inner products on manifolds, there is some interaction. But I would recommend to discuss that elsewhere. In short: We can have a ConnectionManifold that uses a metric to introduce the christoffel symbols and such and vice versa I think.


This PR should be finished now (despite bumping to `0.12.0`.

mateuszbaran: > The MetricManifold needs a little update anyways, and the group manifold will get its own transparency type I think and then I will rework, that anyways.
> While it is breaking here, it should be nonbreaking for them, though.

Nice, though it still would make sense to switch its transparency declarations to loops just like here.

> Do you mean `ConnectionManifold`? Sure, since both metric and connection are a similar way to provide the inner products on manifolds, there is some interaction. But I would recommend to discuss that elsewhere. In short: We can have a ConnectionManifold that uses a metric to introduce the christoffel symbols and such and vice versa I think.

The thing is that connections don't provide inner products while overriding lots of other structure like exp, log or parallel transport.
kellertuer: > Nice, though it still would make sense to switch its transparency declarations to loops just like here.

Sure, I will do that for them in the rework; but that is also nonbreaking

> 
> > Do you mean `ConnectionManifold`? Sure, since both metric and connection are a similar way to provide the inner products on manifolds, there is some interaction. But I would recommend to discuss that elsewhere. In short: We can have a ConnectionManifold that uses a metric to introduce the christoffel symbols and such and vice versa I think.
> 
> The thing is that connections don't provide inner products while overriding lots of other structure like exp, log or parallel transport.

Ah, right. Well we have to be careful there, but the transparency type will surely help. And we can have the LeviCevitaConnection type where it (again) is non overriding but tranparent to its metric.

Patch:
diff --git a/Project.toml b/Project.toml
index 68c46c73..595f3371 100644
--- a/Project.toml
+++ b/Project.toml
@@ -1,7 +1,7 @@
 name = "ManifoldsBase"
 uuid = "3362f125-f0bb-47a3-aa74-596ffd7ef2fb"
 authors = ["Seth Axen <seth.axen@gmail.com>", "Mateusz Baran <mateuszbaran89@gmail.com>", "Ronny Bergmann <manopt@ronnybergmann.net>", "Antoine Levitt <antoine.levitt@gmail.com>"]
-version = "0.11.4"
+version = "0.12.0"
 
 [deps]
 LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
diff --git a/README.md b/README.md
index 98194112..2219eded 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,7 @@
 [![](https://img.shields.io/badge/docs-dev-blue.svg)](https://juliamanifolds.github.io/Manifolds.jl/latest/interface.html)
 [![Build Status](https://travis-ci.org/JuliaManifolds/ManifoldsBase.jl.svg?branch=master)](https://travis-ci.org/JuliaManifolds/ManifoldsBase.jl/)
 [![codecov.io](http://codecov.io/github/JuliaManifolds/ManifoldsBase.jl/coverage.svg?branch=master)](https://codecov.io/gh/JuliaManifolds/ManifoldsBase.jl/)
+[![arXiv](https://img.shields.io/badge/arXiv%20CS.MS-2106.08777-blue.svg)](https://arxiv.org/abs/2106.08777)
 
 Basic interface for manifolds in Julia.
 
@@ -57,3 +58,16 @@ by type.
 
 This adds a semantic layer to the interface, and the default implementation of
 `ValidationManifold` adds checks to all inputs and outputs of typed data.
+
+## Citation
+If you use `ManifoldsBase.jl` in your work, please cite the following
+
+```biblatex
+@online{2106.08777,
+Author = {Seth D. Axen and Mateusz Baran and Ronny Bergmann and Krzysztof Rzecki},
+Title = {Manifolds.jl: An Extensible Julia Framework for Data Analysis on Manifolds},
+Year = {2021},
+Eprint = {2106.08777},
+Eprinttype = {arXiv},
+}
+```
diff --git a/src/DecoratorManifold.jl b/src/DecoratorManifold.jl
index d96c0b6e..6e777816 100644
--- a/src/DecoratorManifold.jl
+++ b/src/DecoratorManifold.jl
@@ -78,11 +78,33 @@ function _split_function(ex::Expr)
     return (; body = body, _split_signature(sig)...)
 end
 
+#
+# Transparency types
+#
+"""
+    AbstractDecoratorType
+
+Decorator types can be used to specify a basic transparency for an [`AbstractDecoratorManifold`](@ref).
+This can be seen as an initial (rough) transparency pattern to start a type with.
+
+Note that for a function `f` and it's mutating variant `f!`
+* The function `f` is set to `:parent` to first invoke allocation and call of `f!`
+* The mutating function `f!` is set to `transparent`
+"""
+abstract type AbstractDecoratorType end
+
+"""
+    DefaultDecoratorType <: AbstractDecoratorType
+
+A default decorator type, where all new functions are transparent by default.
+"""
+struct DefaultDecoratorType <: AbstractDecoratorType end
+
 #
 # Type
 #
 """
-    AbstractDecoratorManifold{𝔽} <: AbstractManifold{𝔽}
+    AbstractDecoratorManifold{𝔽,T<:AbstractDecoratorType} <: AbstractManifold{𝔽}
 
 An `AbstractDecoratorManifold` indicates that to some extent a manifold subtype
 decorates another [`AbstractManifold`](@ref) in the sense that it either
@@ -100,8 +122,15 @@ are transparent for all decorators.
 Transparency of functions with respect to decorators can be specified using the macros
 [`@decorator_transparent_fallback`](@ref), [`@decorator_transparent_function`](@ref) and
 [`@decorator_transparent_signature`](@ref).
+
+There are currently three modes given a new `AbstractDecoratorManifold` `M`
+* `:intransparent` – this function has to be implmented for the new manifold `M`
+* `:transparent` – this function is transparent, in the sense that the function is invoked
+  on the decorated `M.manifold`. This is the default, when introducing a function or signature.
+* `:parent` specifies that (unless implemented) for this function, the classical inheritance
+  is issued, i.e. the function is invoked on `M`s supertype.
 """
-abstract type AbstractDecoratorManifold{𝔽} <: AbstractManifold{𝔽} end
+abstract type AbstractDecoratorManifold{𝔽,T<:AbstractDecoratorType} <: AbstractManifold{𝔽} end
 
 #
 # Macros
@@ -439,7 +468,7 @@ Return whether by default to dispatch the the inner manifold of
 a decorator (`Val(true)`) or not (`Val(false`). For more details see
 [`is_decorator_transparent`](@ref).
 """
-default_decorator_dispatch(M::AbstractManifold) = Val(false)
+default_decorator_dispatch(::AbstractManifold) = Val(false)
 
 """
     is_decorator_transparent(f, M::AbstractManifold, args...) -> Bool
@@ -467,7 +496,7 @@ function is `Val(:transparent)` or `Val(:intransparent)` for the (decorated)
 the function `f` should invoke `M`s `Val(:parent)` implementation, see
 [`@decorator_transparent_function`](@ref) for details.
 """
-decorator_transparent_dispatch(f, M::AbstractManifold, args...) = Val(:transparent)
+decorator_transparent_dispatch(::Any, ::AbstractManifold, args...) = Val(:transparent)
 
 function _acts_transparently(f, M::AbstractManifold, args...)
     return _val_or(
@@ -739,8 +768,36 @@ decorated_manifold(M::AbstractManifold) = M.manifold
 #
 Base.@propagate_inbounds function Base.getindex(
     p::AbstractArray,
-    M::AbstractDecoratorManifold,
+    M::AbstractDecoratorManifold{𝔽,<:AbstractDecoratorType},
     I::Union{Integer,Colon,AbstractVector}...,
-)
+) where {𝔽}
     return getindex(p, decorated_manifold(M), I...)
 end
+
+DEFAULT_PARENT_FUNCTIONS = [
+    distance,
+    exp,
+    inner,
+    inverse_retract,
+    log,
+    mid_point,
+    norm,
+    retract,
+    vector_transport_along,
+    vector_transport_direction,
+    vector_transport_to,
+]
+
+for f in DEFAULT_PARENT_FUNCTIONS
+    eval(
+        quote
+            function decorator_transparent_dispatch(
+                ::typeof($f),
+                ::AbstractDecoratorManifold{𝔽,<:AbstractDecoratorType},
+                args...,
+            ) where {𝔽}
+                return Val(:parent)
+            end
+        end,
+    )
+end
diff --git a/src/EmbeddedManifold.jl b/src/EmbeddedManifold.jl
index 5106603e..3cd1fdbc 100644
--- a/src/EmbeddedManifold.jl
+++ b/src/EmbeddedManifold.jl
@@ -1,9 +1,9 @@
 """
-    AbstractEmbeddingType
+    AbstractEmbeddingType <: AbstractDecoratorType
 
 A type used to specify properties of an [`AbstractEmbeddedManifold`](@ref).
 """
-abstract type AbstractEmbeddingType end
+abstract type AbstractEmbeddingType <: AbstractDecoratorType end
 
 """
     AbstractEmbeddedManifold{𝔽,T<:AbstractEmbeddingType,𝔽} <: AbstractDecoratorManifold{𝔽}
@@ -28,7 +28,7 @@ Technically this is realised by making the [`AbstractEmbeddedManifold`](@ref) is
 for the [`AbstractManifold`](@ref)s that are subtypes.
 """
 abstract type AbstractEmbeddedManifold{𝔽,T<:AbstractEmbeddingType} <:
-              AbstractDecoratorManifold{𝔽} end
+              AbstractDecoratorManifold{𝔽,T} end
 
 """
     DefaultEmbeddingType <: AbstractEmbeddingType
@@ -92,7 +92,7 @@ Generate the `EmbeddedManifold` of the [`AbstractManifold`](@ref) `M` into the
 [`AbstractManifold`](@ref) `N`.
 """
 struct EmbeddedManifold{𝔽,MT<:AbstractManifold{𝔽},NT<:AbstractManifold} <:
-       AbstractDecoratorManifold{𝔽}
+       AbstractDecoratorManifold{𝔽,AbstractDecoratorType}
     manifold::MT
     embedding::NT
 end
@@ -127,14 +127,14 @@ representing the embedding, the base_manifold is the manifold itself in the sens
 detemining e.g. the [`is_default_metric`](@ref) does not fall back to check with
 the embedding but with the manifold itself. For this abstract case, just `M` is returned.
 """
-base_manifold(M::AbstractEmbeddedManifold, d::Val{N} = Val(-1)) where {N} = M
+base_manifold(M::AbstractEmbeddedManifold, ::Val{N} = Val(-1)) where {N} = M
 """
     base_manifold(M::EmbeddedManifold, d::Val{N} = Val(-1))
 
 Return the base manifold of `M` that is enhanced with its embedding. For this specific
 type the internally stored enhanced manifold `M.manifold` is returned.
 """
-base_manifold(M::EmbeddedManifold, d::Val{N} = Val(-1)) where {N} = M.manifold
+base_manifold(M::EmbeddedManifold, ::Val{N} = Val(-1)) where {N} = M.manifold
 
 
 """
@@ -228,400 +228,183 @@ This is used by the [`AbstractDecoratorManifold`](@ref) within
 [`default_decorator_dispatch`](@ref).
 By default this is set to `Val(false)`.
 """
-default_embedding_dispatch(M::AbstractEmbeddedManifold) = Val(false)
-
-function decorator_transparent_dispatch(
-    ::typeof(check_point),
-    ::AbstractEmbeddedManifold,
-    args...,
-)
-    return Val(:intransparent)
-end
-function decorator_transparent_dispatch(
-    ::typeof(check_vector),
-    ::AbstractEmbeddedManifold,
-    args...,
-)
-    return Val(:intransparent)
-end
-function decorator_transparent_dispatch(
-    ::typeof(distance),
-    ::AbstractEmbeddedManifold,
-    args...,
-)
-    return Val(:parent)
-end
-function decorator_transparent_dispatch(
-    ::typeof(distance),
-    ::AbstractEmbeddedManifold{𝔽,TransparentIsometricEmbedding},
-    args...,
-) where {𝔽}
-    return Val(:transparent)
-end
-function decorator_transparent_dispatch(
-    ::typeof(embed),
-    ::AbstractEmbeddedManifold,
-    args...,
-)
-    return Val(:parent)
-end
-function decorator_transparent_dispatch(::typeof(embed), ::EmbeddedManifold, args...)
-    return Val(:intransparent)
-end
-function decorator_transparent_dispatch(
-    ::typeof(embed!),
-    ::AbstractEmbeddedManifold,
-    args...,
-)
-    return Val(:intransparent)
-end
-function decorator_transparent_dispatch(::typeof(exp), ::AbstractEmbeddedManifold, args...)
-    return Val(:parent)
-end
-function decorator_transparent_dispatch(
-    ::typeof(exp),
-    ::AbstractEmbeddedManifold{𝔽,<:TransparentIsometricEmbedding},
-    args...,
-) where {𝔽}
-    return Val(:transparent)
-end
-function decorator_transparent_dispatch(::typeof(exp!), ::AbstractEmbeddedManifold, args...)
-    return Val(:intransparent)
-end
-function decorator_transparent_dispatch(
-    ::typeof(exp!),
-    ::AbstractEmbeddedManifold{𝔽,<:TransparentIsometricEmbedding},
-    args...,
-) where {𝔽}
-    return Val(:transparent)
-end
-function decorator_transparent_dispatch(
-    ::typeof(get_basis),
-    ::AbstractEmbeddedManifold,
-    args...,
-)
-    return Val(:parent)
-end
-function decorator_transparent_dispatch(
-    ::typeof(get_coordinates),
-    ::AbstractEmbeddedManifold,
-    args...,
-)
-    return Val(:parent)
-end
-function decorator_transparent_dispatch(
-    ::typeof(get_coordinates!),
-    ::AbstractEmbeddedManifold,
-    args...,
-)
-    return Val(:parent)
-end
-function decorator_transparent_dispatch(
-    ::typeof(get_vector),
-    ::AbstractEmbeddedManifold,
-    args...,
-)
-    return Val(:parent)
-end
-function decorator_transparent_dispatch(
-    ::typeof(get_vector!),
-    ::AbstractEmbeddedManifold,
-    args...,
-)
-    return Val(:parent)
-end
-function decorator_transparent_dispatch(
-    ::typeof(inner),
-    ::AbstractEmbeddedManifold,
-    args...,
-)
-    return Val(:intransparent)
-end
-function decorator_transparent_dispatch(
-    ::typeof(inner),
-    ::AbstractEmbeddedManifold{𝔽,<:AbstractIsometricEmbeddingType},
-    args...,
-) where {𝔽}
-    return Val(:transparent)
+default_embedding_dispatch(::AbstractEmbeddedManifold) = Val(false)
+
+#
+# Abstract intransparent – i.e. new implementations necessary
+for f in
+    [check_point, check_vector, embed!, exp!, inner, log!, manifold_dimension, project!]
+    eval(
+        quote
+            function decorator_transparent_dispatch(
+                ::typeof($f),
+                ::AbstractEmbeddedManifold,
+                args...,
+            )
+                return Val(:intransparent)
+            end
+        end,
+    )
 end
-function decorator_transparent_dispatch(
-    ::typeof(inverse_retract),
-    ::AbstractEmbeddedManifold,
-    args...,
-)
-    return Val(:parent)
+#
+# Abstract parent – i.e. pass to embedding
+for f in [
+    embed,
+    get_basis,
+    get_coordinates,
+    get_coordinates!,
+    get_vector,
+    get_vector!,
+    inverse_retract!,
+    mid_point!,
+    project,
+    retract!,
+    vector_transport_along,
+    vector_transport_direction,
+    vector_transport_to,
+]
+    eval(
+        quote
+            function decorator_transparent_dispatch(
+                ::typeof($f),
+                ::AbstractEmbeddedManifold,
+                args...,
+            )
+                return Val(:parent)
+            end
+        end,
+    )
 end
-function decorator_transparent_dispatch(
-    ::typeof(inverse_retract),
-    ::AbstractEmbeddedManifold{𝔽,<:TransparentIsometricEmbedding},
-    args...,
-) where {𝔽}
-    return Val(:transparent)
+# Abstract generic isometric
+for f in [inverse_retract!, retract!]
+    eval(
+        quote
+            function decorator_transparent_dispatch(
+                ::typeof($f),
+                ::AbstractEmbeddedManifold{𝔽,<:AbstractIsometricEmbeddingType},
+                args...,
+            ) where {𝔽}
+                return Val(:parent)
+            end
+        end,
+    )
 end
-function decorator_transparent_dispatch(
-    ::typeof(inverse_retract!),
-    ::AbstractEmbeddedManifold,
-    args...,
-)
-    return Val(:parent)
+for f in [norm, inner]
+    eval(
+        quote
+            function decorator_transparent_dispatch(
+                ::typeof($f),
+                ::AbstractEmbeddedManifold{𝔽,<:AbstractIsometricEmbeddingType},
+                args...,
+            ) where {𝔽}
+                return Val(:transparent)
+            end
+        end,
+    )
 end
-function decorator_transparent_dispatch(
-    ::typeof(inverse_retract!),
-    ::AbstractEmbeddedManifold{𝔽,<:AbstractIsometricEmbeddingType},
-    args...,
-) where {𝔽}
-    return Val(:parent)
+#
+# Transparent Isometric Embedding – additionally transparent
+for f in [
+    distance,
+    exp,
+    exp!,
+    inner,
+    inverse_retract,
+    inverse_retract!,
+    log,
+    log!,
+    mid_point,
+    mid_point!,
+    project!,
+    project,
+    retract,
+    retract!,
+    vector_transport_along,
+    vector_transport_direction,
+    vector_transport_to,
+]
+    eval(
+        quote
+            function decorator_transparent_dispatch(
+                ::typeof($f),
+                ::AbstractEmbeddedManifold{𝔽,<:TransparentIsometricEmbedding},
+                args...,
+            ) where {𝔽}
+                return Val(:transparent)
+            end
+        end,
+    )
 end
-function decorator_transparent_dispatch(
-    ::typeof(inverse_retract!),
-    ::AbstractEmbeddedManifold{𝔽,<:TransparentIsometricEmbedding},
-    args...,
-) where {𝔽}
-    return Val(:transparent)
+#
+# For explicit EmbeddingManifolds the following have to be reimplemented (:intransparent)
+for f in [embed, project]
+    eval(
+        quote
+            function decorator_transparent_dispatch(
+                ::typeof($f),
+                ::EmbeddedManifold,
+                args...,
+            )
+                return Val(:intransparent)
+            end
+        end,
+    )
 end
 
-function decorator_transparent_dispatch(::typeof(log), ::AbstractEmbeddedManifold, args...)
-    return Val(:parent)
-end
-function decorator_transparent_dispatch(
-    ::typeof(log),
-    ::AbstractEmbeddedManifold{𝔽,<:TransparentIsometricEmbedding},
-    args...,
-) where {𝔽}
-    return Val(:transparent)
-end
-function decorator_transparent_dispatch(::typeof(log!), ::AbstractEmbeddedManifold, args...)
-    return Val(:intransparent)
-end
-function decorator_transparent_dispatch(
-    ::typeof(log!),
-    ::AbstractEmbeddedManifold{𝔽,<:TransparentIsometricEmbedding},
-    args...,
-) where {𝔽}
-    return Val(:transparent)
-end
-function decorator_transparent_dispatch(
-    ::typeof(mid_point),
-    ::AbstractEmbeddedManifold,
-    args...,
-)
-    return Val(:parent)
-end
-function decorator_transparent_dispatch(
-    ::typeof(mid_point),
-    ::AbstractEmbeddedManifold{𝔽,<:TransparentIsometricEmbedding},
-    args...,
-) where {𝔽}
-    return Val(:transparent)
-end
-function decorator_transparent_dispatch(
-    ::typeof(mid_point!),
-    ::AbstractEmbeddedManifold,
-    args...,
-)
-    return Val(:parent)
-end
-function decorator_transparent_dispatch(
-    ::typeof(mid_point!),
-    ::AbstractEmbeddedManifold{𝔽,<:TransparentIsometricEmbedding},
-    args...,
-) where {𝔽}
-    return Val(:transparent)
-end
-function decorator_transparent_dispatch(::typeof(norm), ::AbstractEmbeddedManifold, args...)
-    return Val(:parent)
-end
-function decorator_transparent_dispatch(
-    ::typeof(norm),
-    ::AbstractEmbeddedManifold{𝔽,<:AbstractIsometricEmbeddingType},
-    args...,
-) where {𝔽}
-    return Val(:transparent)
-end
-function decorator_transparent_dispatch(
-    ::typeof(manifold_dimension),
-    ::AbstractEmbeddedManifold,
-    args...,
-)
-    return Val(:intransparent)
-end
-function decorator_transparent_dispatch(
-    ::typeof(project!),
-    ::AbstractEmbeddedManifold,
-    args...,
-)
-    return Val(:intransparent)
-end
-function decorator_transparent_dispatch(
-    ::typeof(project!),
-    ::AbstractEmbeddedManifold{𝔽,<:TransparentIsometricEmbedding},
-    args...,
-) where {𝔽}
-    return Val(:transparent)
-end
-function decorator_transparent_dispatch(
-    ::typeof(project),
-    ::AbstractEmbeddedManifold,
-    args...,
-)
-    return Val(:parent)
-end
-function decorator_transparent_dispatch(
-    ::typeof(project),
-    ::AbstractEmbeddedManifold{𝔽,<:TransparentIsometricEmbedding},
-    args...,
-) where {𝔽}
-    return Val(:transparent)
-end
-function decorator_transparent_dispatch(::typeof(project), ::EmbeddedManifold, args...)
-    return Val(:intransparent)
-end
-function decorator_transparent_dispatch(
-    ::typeof(retract),
-    ::AbstractEmbeddedManifold,
-    args...,
-)
-    return Val(:parent)
-end
-function decorator_transparent_dispatch(
-    ::typeof(retract),
-    ::AbstractEmbeddedManifold{𝔽,<:TransparentIsometricEmbedding},
-    args...,
-) where {𝔽}
-    return Val(:transparent)
-end
-function decorator_transparent_dispatch(
-    ::typeof(retract!),
-    ::AbstractEmbeddedManifold,
-    args...,
-)
-    return Val(:parent)
-end
-function decorator_transparent_dispatch(
-    ::typeof(retract!),
-    ::AbstractEmbeddedManifold{𝔽,<:AbstractIsometricEmbeddingType},
-    args...,
-) where {𝔽}
-    return Val(:parent)
-end
-function decorator_transparent_dispatch(
-    ::typeof(retract!),
-    ::AbstractEmbeddedManifold{𝔽,<:TransparentIsometricEmbedding},
-    args...,
-) where {𝔽}
-    return Val(:transparent)
-end
-function decorator_transparent_dispatch(
-    ::typeof(vector_transport_along),
-    ::AbstractEmbeddedManifold,
-    args...,
-)
-    return Val(:parent)
-end
-function decorator_transparent_dispatch(
-    ::typeof(vector_transport_along),
-    ::AbstractEmbeddedManifold{𝔽,<:TransparentIsometricEmbedding},
-    args...,
-) where {𝔽}
-    return Val(:transparent)
-end
-function decorator_transparent_dispatch(
-    ::typeof(vector_transport_along!),
-    ::AbstractEmbeddedManifold,
-    args...,
-)
-    return Val(:intransparent)
-end
-function decorator_transparent_dispatch(
-    ::typeof(vector_transport_along!),
-    ::AbstractEmbeddedManifold{𝔽,<:TransparentIsometricEmbedding},
-    args...,
-) where {𝔽}
-    return Val(:transparent)
-end
-function decorator_transparent_dispatch(
-    ::typeof(vector_transport_direction),
-    ::AbstractEmbeddedManifold,
-    args...,
-)
-    return Val(:parent)
-end
-function decorator_transparent_dispatch(
-    ::typeof(vector_transport_direction),
-    ::AbstractEmbeddedManifold{𝔽,<:TransparentIsometricEmbedding},
-    args...,
-) where {𝔽}
-    return Val(:transparent)
-end
-function decorator_transparent_dispatch(
-    ::typeof(vector_transport_direction!),
-    ::AbstractEmbeddedManifold,
-    args...,
-)
-    return Val(:parent)
-end
-function decorator_transparent_dispatch(
-    ::typeof(vector_transport_direction!),
-    ::AbstractEmbeddedManifold{𝔽,<:TransparentIsometricEmbedding},
-    args...,
-) where {𝔽}
-    return Val(:transparent)
-end
-function decorator_transparent_dispatch(
-    ::typeof(vector_transport_to),
-    ::AbstractEmbeddedManifold,
-    args...,
-)
-    return Val(:parent)
-end
-function decorator_transparent_dispatch(
-    ::typeof(vector_transport_to),
-    ::AbstractEmbeddedManifold{𝔽,<:TransparentIsometricEmbedding},
-    args...,
-) where {𝔽}
-    return Val(:transparent)
-end
-function decorator_transparent_dispatch(
-    ::typeof(vector_transport_to!),
-    ::AbstractEmbeddedManifold{𝔽,<:E},
-    Y,
-    p,
-    X,
-    q,
-    ::T,
-) where {𝔽,T,E}
-    return Val(:intransparent)
-end
-function decorator_transparent_dispatch(
-    ::typeof(vector_transport_to!),
-    ::AbstractEmbeddedManifold{𝔽,<:E},
-    Y,
-    p,
-    X,
-    q,
-    ::Union{PoleLadderTransport,SchildsLadderTransport},
-) where {𝔽,E}
-    return Val(:parent)
-end
-function decorator_transparent_dispatch(
-    ::typeof(vector_transport_to!),
-    ::AbstractEmbeddedManifold{𝔽,<:TransparentIsometricEmbedding},
-    Y,
-    p,
-    X,
-    q,
-    ::Union{PoleLadderTransport,SchildsLadderTransport},
-) where {𝔽}
-    return Val(:parent)
-end
-function decorator_transparent_dispatch(
-    ::typeof(vector_transport_to!),
-    ::AbstractEmbeddedManifold{𝔽,<:TransparentIsometricEmbedding},
-    Y,
-    p,
-    X,
-    q,
-    ::T,
-) where {𝔽,T}
-    return Val(:transparent)
+# unified vector transports for the three already implemented cases.
+for f in [vector_transport_along!, vector_transport_direction!, vector_transport_to!]
+    eval(
+        quote
+            function decorator_transparent_dispatch(
+                ::typeof($f),
+                ::AbstractEmbeddedManifold{𝔽,<:E},
+                Y,
+                p,
+                X,
+                q,
+                ::T,
+            ) where {𝔽,T,E}
+                return Val(:intransparent)
+            end
+            function decorator_transparent_dispatch(
+                ::typeof($f),
+                ::AbstractEmbeddedManifold{𝔽,<:TransparentIsometricEmbedding},
+                Y,
+                p,
+                X,
+                q,
+                ::T,
+            ) where {𝔽,T}
+                return Val(:transparent)
+            end
+        end,
+    )
+    for m in [PoleLadderTransport, SchildsLadderTransport, ScaledVectorTransport]
+        eval(
+            quote
+                function decorator_transparent_dispatch(
+                    ::typeof($f),
+                    ::AbstractEmbeddedManifold{𝔽,<:E},
+                    Y,
+                    p,
+                    X,
+                    q,
+                    ::$m,
+                ) where {𝔽,E}
+                    return Val(:parent)
+                end
+                function decorator_transparent_dispatch(
+                    ::typeof($f),
+                    ::AbstractEmbeddedManifold{𝔽,<:TransparentIsometricEmbedding},
+                    Y,
+                    p,
+                    X,
+                    q,
+                    ::$m,
+                ) where {𝔽}
+                    return Val(:parent)
+                end
+            end,
+        )
+    end
 end
diff --git a/src/ManifoldsBase.jl b/src/ManifoldsBase.jl
index d8bb0fa5..b9c352dc 100644
--- a/src/ManifoldsBase.jl
+++ b/src/ManifoldsBase.jl
@@ -550,6 +550,8 @@ export AbstractPowerManifold, PowerManifold
 export AbstractPowerRepresentation,
     NestedPowerRepresentation, NestedReplacingPowerRepresentation
 
+export AbstractDecoratorType, DefaultDecoratorType
+
 export OutOfInjectivityRadiusError
 
 export AbstractRetractionMethod,
diff --git a/src/ValidationManifold.jl b/src/ValidationManifold.jl
index 87dbeeca..5ab0fae4 100644
--- a/src/ValidationManifold.jl
+++ b/src/ValidationManifold.jl
@@ -9,7 +9,8 @@ encapsulated/stripped automatically when needed.
 This manifold is a decorator for a manifold, i.e. it decorates a [`AbstractManifold`](@ref) `M`
 with types points, vectors, and covectors.
 """
-struct ValidationManifold{𝔽,M<:AbstractManifold{𝔽}} <: AbstractDecoratorManifold{𝔽}
+struct ValidationManifold{𝔽,M<:AbstractManifold{𝔽}} <:
+       AbstractDecoratorManifold{𝔽,DefaultDecoratorType}
     manifold::M
 end
 
diff --git a/src/bases.jl b/src/bases.jl
index 2ee4a2f0..c7d42f06 100644
--- a/src/bases.jl
+++ b/src/bases.jl
@@ -340,7 +340,7 @@ function combine_allocation_promotion_functions(::typeof(identity), ::typeof(com
 end
 
 @doc raw"""
-    dual_basis(M::AbstractManifold, p, B::AbstractBasis) 
+    dual_basis(M::AbstractManifold, p, B::AbstractBasis)
 
 Get the dual basis to `B`, a basis of a vector space at point `p` from manifold `M`.
 
@@ -533,13 +533,6 @@ for BT in [DISAMBIGUATION_BASIS_TYPES..., DISAMBIGUATION_COTANGENT_BASIS_TYPES..
         end,
     )
 end
-function decorator_transparent_dispatch(
-    ::typeof(get_coordinates!),
-    ::AbstractManifold,
-    args...,
-)
-    return Val(:transparent)
-end
 
 function get_coordinates!(M::AbstractManifold, Y, p, X, B::VeeOrthogonalBasis)
     return get_coordinates!(M, Y, p, X, DefaultOrthogonalBasis(number_system(B)))
@@ -632,9 +625,6 @@ for BT in [DISAMBIGUATION_BASIS_TYPES..., DISAMBIGUATION_COTANGENT_BASIS_TYPES..
         end,
     )
 end
-function decorator_transparent_dispatch(::typeof(get_vector!), ::AbstractManifold, args...)
-    return Val(:transparent)
-end
 
 _get_vector_cache_broadcast(::Any) = Val(true)
 


Test patch:
diff --git a/test/decorator_manifold.jl b/test/decorator_manifold.jl
index e98cffd7..2f49445e 100644
--- a/test/decorator_manifold.jl
+++ b/test/decorator_manifold.jl
@@ -7,11 +7,12 @@ using ManifoldsBase:
     is_decorator_transparent
 import ManifoldsBase: decorator_transparent_dispatch
 
-struct TestDecorator{M<:AbstractManifold{ℝ}} <: AbstractDecoratorManifold{ℝ}
+struct TestDecorator{M<:AbstractManifold{ℝ}} <:
+       AbstractDecoratorManifold{ℝ,DefaultDecoratorType}
     manifold::M
 end
 
-abstract type AbstractTestDecorator <: AbstractDecoratorManifold{ℝ} end
+abstract type AbstractTestDecorator <: AbstractDecoratorManifold{ℝ,DefaultDecoratorType} end
 
 struct TestDecorator2{M<:AbstractManifold{ℝ}} <: AbstractTestDecorator
     manifold::M
@@ -21,13 +22,14 @@ struct TestDecorator3{M<:AbstractManifold{ℝ}} <: AbstractTestDecorator
     manifold::M
 end
 
-abstract type AbstractParentDecorator <: AbstractDecoratorManifold{ℝ} end
+abstract type AbstractParentDecorator <: AbstractDecoratorManifold{ℝ,DefaultDecoratorType} end
 
 struct ChildDecorator{M<:AbstractManifold{ℝ}} <: AbstractParentDecorator
     manifold::M
 end
 
-struct DefaultDecorator{M<:AbstractManifold{ℝ}} <: AbstractDecoratorManifold{ℝ}
+struct DefaultDecorator{M<:AbstractManifold{ℝ}} <:
+       AbstractDecoratorManifold{ℝ,DefaultDecoratorType}
     manifold::M
 end
 ManifoldsBase.default_decorator_dispatch(::DefaultDecorator) = Val(true)
diff --git a/test/embedded_manifold.jl b/test/embedded_manifold.jl
index 4121a5d7..02b54425 100644
--- a/test/embedded_manifold.jl
+++ b/test/embedded_manifold.jl
@@ -276,7 +276,7 @@ struct NotImplementedEmbeddedManifold3 <: AbstractEmbeddedManifold{ℝ,DefaultEm
                   Val(:intransparent)
         end
         @test ManifoldsBase.decorator_transparent_dispatch(vector_transport_along!, AM) ===
-              Val(:intransparent)
+              Val(:transparent)
         @test ManifoldsBase.decorator_transparent_dispatch(
             vector_transport_to!,
             AM,
@@ -289,7 +289,7 @@ struct NotImplementedEmbeddedManifold3 <: AbstractEmbeddedManifold{ℝ,DefaultEm
         @test ManifoldsBase.decorator_transparent_dispatch(
             vector_transport_direction!,
             AM,
-        ) === Val(:parent)
+        ) === Val(:transparent)
 
         for f in [inner, norm]
             @test ManifoldsBase.decorator_transparent_dispatch(f, IM) === Val(:transparent)
diff --git a/test/power.jl b/test/power.jl
index 6e746a48..da3cb248 100644
--- a/test/power.jl
+++ b/test/power.jl
@@ -5,7 +5,7 @@ using StaticArrays
 
 struct DummyPowerRepresentation <: AbstractPowerRepresentation end
 struct DummyDecorator{TM<:AbstractManifold{ManifoldsBase.ℝ}} <:
-       AbstractDecoratorManifold{ManifoldsBase.ℝ}
+       AbstractDecoratorManifold{ManifoldsBase.ℝ,DefaultDecoratorType}
     manifold::TM
 end