control-toolbox / CTBase.jl

Fundamentals of the control-toolbox ecosystem
http://control-toolbox.org/CTBase.jl/
MIT License
12 stars 3 forks source link

Differential geometry #52

Closed ocots closed 6 months ago

ocots commented 1 year ago

@jbcaillau I have introduced more operations to compute controls, multipliers associated to state constraint of order 1, 2 and more, but also to compute singular arcs of any order.

For the moment, I have:

I will add of course Poisson brackets.

I need some validation for the syntax and possibilities. I present in the autonomous case but it works also in the non-autonomous case and in both vectorial and scalar cases.

Lifts

From a VectorField:

julia> X = VectorField(x -> 2x)
julia> H = Lift(X)
julia> H(1, 1)
2

or in 2D:

julia> X = VectorField(x -> 2x)
julia> H = Lift(X)
julia> H([1, 2], [3, 4]) == 22
22

From a function it works also: H = Lift(x -> 2x).

Lie derivatives

julia> X = VectorField(x -> [x[2], -x[1]])
julia> f = x -> x[1]^2 + x[2]^2
julia> (X⋅f)([1, 2]) # or Ad(X, f)([1, 2])
0

Between two vector fields.

julia> X = VectorField(x -> [x[2], -x[1]])
julia> Y = VectorField(x -> [x[1], x[2]])
julia> (X⋅Y)([1, 2]) # or Ad(X, Y)([1, 2])
[2, -1]

You can also do:

julia> X = VectorField(x -> [x[2], -2x[1]])
julia> Y = VectorField(x -> [x[1], 3x[2]])
julia> f = x -> x[1]^2 + 2x[2]^2
julia> (X⋅Y⋅f)([1, 2])

Lie brackets

julia> X = VectorField(x -> [x[2], -x[1]])
julia> Y = VectorField(x -> [x[2], -x[1]])
julia> Lie(X, Y)([1, 2])
[0, 0]

You can use the argument order to specify the bracket you want. For instance, let us consider

x = [1, 2, 3]
Γ = 2
γ = 1
δ = γ-Γ
F0 = VectorField(x -> [-Γ*x[1], -Γ*x[2], γ*(1-x[3])])
F1 = VectorField(x -> [0, -x[3], x[2]])
F2 = VectorField(x -> [x[3], 0, -x[1]])

Then,

F01 = Lie(F0, F1)

is equivalent to

F01 = Lie(F0, F1, order=(1, 2))
# or
F01 = Lie(F0, F1, F2, order=(1, 2))
# or
F01 = Lie(F2, F0, F1, order=(2, 3))

We can also compute:

F120 = Lie(F0, F1, F2, order=(2,3,1))

If you want several Lie brackets of different lengths, you can do

F01 = Lie(F0, F1)
F012 = Lie(F01, F2)

or for others

F12, F121, F122 = Lie(F1, F2, orders=((1,2), (1,2,1), (1, 2, 2)))

Note that it is not so practical to give the orders like that so I have introduced the possibility to give labels:

x = [1, 2, 3]
Γ = 2
γ = 1
δ = γ-Γ
F0 = VectorField(x -> [-Γ*x[1], -Γ*x[2], γ*(1-x[3])], label=:F0)
F1 = VectorField(x -> [0, -x[3], x[2]], label=:F1)
F2 = VectorField(x -> [x[3], 0, -x[1]], label=:F2)

Then, you can do

F12, F121, F122 = Lie(F1, F2, orders=((:F1, :F2), (:F1, :F2, :F1), (:F1, :F2, :F2)))
jbcaillau commented 1 year ago

Very nice. Not sure to understand the "order" you introduced. (Seems to me that composing brackets in readable, and enough for applications.) One could alternatively define a macro so that

@Lie F10001

computed

Lie(F1, Lie(F0, ..., Lie(F0, F1)...)

(And similarly for Poisson brackets, e.g. Lie bracket and lifts.)

NB. A bit confused by your notations as

[X,Y] = X\cdot Y-Y\cdot X = \mathrm{ad}_X (Y) (\neq X\cdot Y).
ocots commented 1 year ago

Ok I will make a pass on the notations. I used Ad since it was already existing.

The name order is not good I guess, I will find something else or remove it. The idea was to give all the vector fields to the function Lie, and then, composed them to make Lie brackets by giving something like F10001 but I have chosen to give the indices of the vector fields in the function.

F10 = Lie(F0, F1, F2, order=(2, 1))
F10001, F21, F201 = Lie(F0, F1, F2, orders=((2, 1, 1, 1, 2), (3, 2), (3, 1, 2))

F1 is at the second place while F0 is at the first one so to compute F10 you give the "order" (2, 1). I started from 1 since you can also write (you can switch places or have different names):

F10 = Lie(F2, F1, F0, order=(2, 3))
XY = Lie(X, Y, Z, order=(1, 2))

And I had introduced labels if giving the index was no so clear.

I guess I can write you macro which calls my function. Do you prefer:

@Lie F10001
@Lie F21
@Lie F201

or

@Lie F10001, F21, F201
ocots commented 1 year ago

Some changes:

# lift
H = Lift(X) # H(x, p) = p⋅X(x)

# directional derivatives
Der(X, f)(x) = (X⋅f)(x) = Lie(X, f)(x) # = f'(x)⋅X(x)
Der(X, Y)(x) = (X⋅Y)(x) # = JY(x) X(x) 

# Lie brackets
Lie(X, Y) = ad(X, Y)= X⋅Y-Y⋅X # = [X, Y] 
Lie(X, Y, Z, sequence=(1, 3)) # = [X, Z]
Lie(X, Y, Z, sequence=(1, 3, 2)) # = [[X, Z], Y]
Lie(X, Y, Z, sequences=((1, 3), (1, 3, 2))) # = [X, Z], [[X, Z], Y]
Lie(X, Y, Z, sequence=(:X, :Z)) # = [X, Z], if the vector fields have labels
@Lie F012 # F012 = [[F0, F1], F2]

But I don't manage to write a macro to compute several brackets in one line:

@Lie F01, F12, F101

Here is the macro for one bracket:

function _Lie(expr::Symbol)
    v = split(string(expr))[1]
    @assert v[1] == 'F'
    uni = sort(unique(v[2:end]))
    vfs = Tuple([Symbol(:F, n) for n ∈ uni])
    seq = [parse(Integer, c) for c ∈ v[2:end]]
    sequence = Tuple([findfirst(v->v==s, parse.(Integer, uni)) for s ∈ seq])
    code = quote
        $expr = Lie($(vfs...), sequence=$sequence)
    end
    return code
end

macro Lie(expr::Symbol)
    esc(_Lie(expr))
end

and this for several:

macro Lie(expr::Expr)
    @assert hasproperty(expr, :head)
    (@assert(s isa Symbol) for s ∈ expr.args)
    dump(expr)
    eval.([_Lie(s) for s ∈ expr.args])
end

But I want to remove eval. Any help?

jbcaillau commented 1 year ago

@ocots not sure about what you want to do but: regarding eval, you should be able to write your loop inside the generated code.

You want to compute several brackets to save time, right? Since, for instance, you need $F{01}$ to compute $F{001}$?

ocots commented 1 year ago

It was just to compute several brackets in one line with one call to @Lie. Not very useful.

Instead, I suggest this:

XY = @Lie [X, Y]
F = @Lie [[X, Y], [[X, Y], Z]]

To compute any Lie bracket.

jbcaillau commented 1 year ago

ouh, nice shot mr @ocots! I did not even thought of macro to access [ ] brackets. Well done. Same for Poisson, BTW.

ocots commented 1 year ago

To sum up, I have:

# lift
H = Lift(X) # H(x, p) = p⋅X(x)

# directional derivatives
Der(X, f)(x) = (X⋅f)(x) = Lie(X, f)(x) # = f'(x)⋅X(x)
Der(X, Y)(x) = (X⋅Y)(x) # = JY(x) X(x) 

# Lie brackets
Lie(X, Y) = ad(X, Y)= X⋅Y-Y⋅X = @Lie [X, Y] # = [X, Y] 
F = @Lie [[X, Y], [[X, Y], Z]]
@Lie F012 # F012 = [[F0, F1], F2]

I have removed "sequence" and "labels".

Go to Poisson!

ocots commented 1 year ago

todo: remove Der(X,Y) and check Lie(X, Y) with the real intrinsic order 2 definition.

jbcaillau commented 1 year ago

Yes:

@test ((@Lie [ X, Y ])⋅f)(x) == ((X⋅(Y⋅f))(x) - (Y⋅(X⋅f))(x)
ocots commented 1 year ago

Test passed:

        @testset "intrinsic definition" begin

            X = VectorField(x -> [x[2]^2, -2x[1]*x[2]])
            Y = VectorField(x -> [x[1]*(1+x[2]), 3x[2]^3])
            f = x -> x[1]^4 + 2x[2]^3
            x = [1, 2]

            # check real intrinsic order 2 definition of Lie bracket
            Test.@test ((@Lie [ X, Y ])⋅f)(x) == ((X⋅(Y⋅f))(x) - (Y⋅(X⋅f))(x))

        end
ocots commented 1 year ago

Ok what we have now:

# lift
H = Lift(X) # H(x, p) = p⋅X(x)

# directional derivatives
Lie(X, f)(x) = Der(X, f)(x) = (X⋅f)(x) # = f'(x)⋅X(x)

# Lie brackets
Lie(X, Y) = ad(X, Y) = @Lie [X, Y] # = [X, Y] 
F = @Lie [[X, Y], [[X, Y], Z]]
@Lie F012 # F012 = [[F0, F1], F2]
ocots commented 1 year ago

Still WIP.

ocots commented 1 year ago

@BaptisteCbl About the file differential_geometry.jl of the branch diff-geometry.

Some updates have to be done and some features have to be added.

Remove the macro to compute Lie brackets from a Symbol: @Lie F012

Since we can compute any Lie bracket simply doing

F012 = @Lie [[F0, F1], F2]

the macro

@Lie F012 # F012 = [[F0, F1], F2]

is not useful anymore. This part of the code should be removed and the unit tests must be updated:

# type
const Sequence = Tuple{Vararg{Integer}}

# default value of a sequence of vector fields to compute one Lie bracket
__fun_sequence(Xs::VectorField...) = Tuple(1:length(Xs))

#
function _Lie_sequence(Xs::VectorField{td, sd}...; sequence::Sequence=__fun_sequence(Xs...))::VectorField{td, sd} where {td, sd}

    # check length of Xs
    length(Xs) < 2 && throw(IncorrectArgument("Xs must have at least two elements"))

    # check length of sequence
    length(sequence) < 2 && throw(IncorrectArgument("sequence must have at least two elements"))

    # check if the elements of sequence are contained in 1:length(Xs)
    for o ∈ sequence
        o < 1 && throw(IncorrectArgument("sequence must contain only positive integers"))
        o > length(Xs) && throw(IncorrectArgument("sequence must contain only integers less than or equal to the length of Xs"))
    end

    # 
    if length(sequence) == 2
        return Lie(Xs[sequence[1]], Xs[sequence[2]])
    else
        return Lie(_Lie_sequence(Xs..., sequence=sequence[1:end-1]), Xs[sequence[end]])
    end

end

macro Lie(expr::Symbol)

    # split symbol into substrings
    v = split(string(expr))[1]

    # check if the first character is 'F'
    @assert v[1] == 'F'

    # get the unique numbers in the symbol
    uni = sort(unique(v[2:end]))

    # build the tuple of needed vector fields
    vfs = Tuple([Symbol(:F, n) for n ∈ uni])

    # build the sequence to compute the Lie bracket
    user_sequence = [parse(Integer, c) for c ∈ v[2:end]] # conversion to integer
    sequence = Tuple([findfirst(v->v==s, parse.(Integer, uni)) for s ∈ user_sequence])

    # build the code
    code = quote
        $expr = _Lie_sequence($(vfs...), sequence=$sequence)
    end

    return esc(code)
end
ocots commented 1 year ago

Then, I have defined

https://github.com/control-toolbox/CTBase.jl/blob/e5b7a3ef2e4be85aacd6d573dde02223894da528/src/differential_geometry.jl#LL6C19-L6C19

which should be updated according to the new parameterization of functions, cf. this comment.

Remark. The Hamiltonian structure must be <: AbstractHamiltonian.

Then, we need to had the Poisson bracket of two AbstractHamiltonian, according to

function Poisson(f, g)
    function fg(x, p)
        n = size(x, 1)
        ff = z -> f(z[1:n], z[n+1:2n])
        gg = z -> g(z[1:n], z[n+1:2n])
        df = ctgradient(ff, [ x ; p ])
        dg = ctgradient(gg, [ x ; p ])
        return df[n+1:2n]'*dg[1:n] - df[1:n]'*dg[n+1:2n]
    end
    return fg
end

See Poisson bracket Wikipedia.

Remark. If the two Hamiltonians are lifts of vector fields, then, there is a relation between the Poisson bracket of the Hamiltonians and the Lie bracket of the associated vector fields, cf. ici (not the best ref.).

BaptisteCbl commented 1 year ago

Hi ! I have made some of the changes in this branch of my fork but it is not finished, I need to add the macro for Poisson (the classic function works) and add tests for it. Also Lift is broken for now because of the update from the original diff-geometry branch to the develop version of CTBase. I'll finish it as soon as possible.

jbcaillau commented 1 year ago

@ocots @BaptisteCbl Hi! Curly brackets { , } that are the standard notation for Poisson brackets are also available via macros, so it is possible to do the same as Olivier did for Lie ones:

julia> @dump { f, g }
Expr
  head: Symbol braces
  args: Array{Any}((2,))
    1: Symbol f
    2: Symbol g

julia> @Poisson { f, { f, g } }

See also

BaptisteCbl commented 1 year ago

Hi, I have added the macro for Poisson and some tests. But before making the pull request I have a question. I still don't know how to handle the variables of the non-fixed functions (VectorField and directional derivative for Lie and AbstractHamiltonian for Poisson), so there is no support for these non-fixed functions at the moment. Does having a Poisson bracket of a variable dependent Hamiltonian have any meaning ? If so, does it have to be treated like the time variable of non autonomous functions ?

ocots commented 1 year ago

It has a meaning to compute Lie or Poisson brackets for functions depending on parameters such as a Variable. However we do not differentiate wrt the parameter. Maybe you can use args....

ocots commented 1 year ago

It has a meaning but it does not change anything in the computation to have a Variable.

ocots commented 1 year ago

However, for non autonomous vector fields or Hamiltonians, we should compute the partial derivative with respect to time in the Lie and Poisson brackets.

@jbcaillau what do you think?

ocots commented 1 year ago

@BaptisteCbl We can speak about that around 15:30 on discord if you want.

BaptisteCbl commented 1 year ago

Yes I would like to, thank you. I sent you a request on Discord but if you want to do it on other platform I'm okay too.

ocots commented 1 year ago

Discord is fine.

ocots commented 1 year ago

I need 10''. Do you find me on discord?

BaptisteCbl commented 1 year ago

Yes, I sent you a friend request and a message.

ocots commented 1 year ago

I can't see it: ocots#3541

jbcaillau commented 1 year ago

@ocots @BaptisteCbl Hi guys, I would say yes: for time dependent functions, it makes sense to include time as an additional variable (for differentiation).

ocots commented 1 year ago

@BaptisteCbl I think you can abort the idea to add partial derivatives with respect to time in the Lie derivative, bracket and Poisson bracket. It seems difficult to have something consistent.we will see with use cases later.

jbcaillau commented 1 year ago

@BaptisteCbl I think you can abort the idea to add partial derivatives with respect to time in the Lie derivative, bracket and Poisson bracket. It seems difficult to have something consistent.we will see with use cases later.

@ocots don't you have an example (irrigation thing...) with time dependent vector fields? it is good to start from a use case an check what kind of computation you need in this setting.

ocots commented 1 year ago

Actually, we need to differentiate in my use cases:

t -> g(t, x(t)) # state constraint
t -> H1(t, x(t), p(t)) # switching function

If we have:

ẋ(t) = F₀(t, x(t)) + u(t) F₁(t, x(t)) # the dynamics
H(t, x, p, u) = H₀(t, x, p) + u H₁(t, x, p) # the pseudo-Hamiltonian
g(t, x) ≤ 0 # the state constraint

We may need to compute:

t -> ∂ₜg(t, x(t)) + ∂ₓg(t, x(t))⋅ẋ(t)
t -> ∂ₜH₁(t, x(t), p(t)) + ∂ₓH₁(t, x(t), p(t))⋅ẋ(t) + ∂ₚH₁(t, x(t), p(t))⋅ẋ(t)

which is given for the moment by:

t -> ∂ₜg(t, x(t)) + Lie(F₁, g)(t, x(t))
t -> ∂ₜH₁(t, x(t), p(t)) + Poisson(H₀, H₁)(t, x(t), p(t))

But I have no example for the Lie bracket of two vector fields.

ocots commented 1 year ago

Considering

(X⋅f)(x) = f'(x)⋅X(x)
(X⋅f)(t, x) = ∂ₜf(t, x) + ∂ₓf(t, x)⋅X(t, x)

It seems difficult in the non-autonomous case to keep properties like the following ones if we add partial derivatives.

[X, Y]⋅f = (X∘Y - Y∘X)⋅f
{f,g}(t, z) = p⋅[X,Y](t, x) 

if

f(t, z) = p⋅X(t, x)
g(t, z) = p⋅Y(t, x)
z = (x, p)

But somehow, we could add a state variable whom dynamics is ṫ = 1 and retrieve an autonomous system. For the Lie derivative, it is exactly what we want. I don't know what happens for the Lie bracket but it should be fine. I am more embarrassed with the Poisson bracket since one dual variable is missing.

jbcaillau commented 1 year ago

@ocots Yes: adding the time as an additional state should work (there is indeed an associated dual variable, $p_t$). A good test is to write things for this example and check whether it remains user friendly, both from the mathematical and coding sides.

ocots commented 1 year ago

Attention, les calculs sont FAUX et d'un point de vue pratique, on n'a pas intérêt à mettre les dérivées partielles par rapport au temps car à la fin on veut calculer le contrôle et on aura toujours à calculer deux crochets et une seule dérivée partielle par rapport au temps.

Pourquoi pas fournir 3 fonctions : ∂ₜ, ∂ₓ et ∂ₚ.


@BaptisteCbl Actually, it is ok. You can code the non-autonomous case with partial derivatives wrt time.

Let X being a vector field and f a differential function. We define

(X⋅f)(t, x) = ∂ₜf(t, x) + ∂ₓf(t, x)⋅X(t, x) # Lie derivative of f along X
[X, Y]⋅f = (X∘Y - Y∘X)⋅f # Lie bracket of X and Y

Then,

([X, Y]⋅f)(t, x) = ∂ₓf(t, x)⋅(∂ₜY(t, x)+∂ₓY(t, x)⋅X(t, x) - (∂ₜX(t, x)+∂ₓX(t, x)⋅Y(t, x)))

which is ok since there is no order 2. We thus define

(X ⅋ Y)(t, x) = ∂ₜY(t, x) + ∂ₓY(t, x)⋅X(t, x) = Y'(t, x)⋅(1, X(t, x))

so that

[X, Y] = X ⅋ Y - Y ⅋ X

For the Poisson bracket, we denote by F the Hamiltonian vector field associated to f, a Hamiltonian now (I cannot write arrows). So:

F(t, z) = (∂ₚf(t, z), -∂ₓf(t, z)) # f(t, z) a non-autonomous Hamiltonian and F its Hamiltonian vector field

We define the Poisson bracket as:

{f, g} = F⋅g # the Lie derivative of g along F

Like this we have what we want since

{f, g}(t, z) = ∂ₜg(t, z) + ∂_z g(t, z)⋅F(t, z)

and let consider for instance that we want to differentiate wrt time t -> g(t, z(t)) with ż(t) = F(t, z(t)). We get

dₜ g(t, z(t)) = ∂ₜg(t, z(t)) + ∂_z g(t, z(t))⋅ż(t) = {f, g}(t, z(t))

The only thing that changes is the following. Assume that

f(t, z) = p⋅X(t, x)
g(t, z) = p⋅Y(t, x)

Then,

{f, g}(t, z) = p⋅([X, Y](t, x) + ∂ₜX(t, x)) 

if I have not made a mistake.

BaptisteCbl commented 1 year ago

Ok, thanks ! I'll try to implement it in #85.

jbcaillau commented 1 year ago

@ocots Seems OK and in line with what you previously said, i.e. adding $t'(s)=1$ with $s$ a new time. Some thoughts:

I suppose that subtyping + dispatch à la {<:TimeDependence} might do the job.

ocots commented 1 year ago

We can reuse code since we can compute Poisson bracket from Lie derivative.

Don't know if it is a good idea to use the autonomous case.

jbcaillau commented 1 year ago

hello mr @ocots!

ocots commented 1 year ago

👋

jbcaillau commented 1 year ago

mollo on coconut milk for breakfast, please 🤭

ocots commented 1 year ago

Et les mangues, excellentes 😁

ocots commented 1 year ago

Recap of what we will have:

Let X being a vector field and f a differentiable function. We define

(X⋅f)(t, x) = ∂ₓf(t, x)⋅X(t, x) # Lie derivative of f along X
[X, Y]⋅f = (X∘Y - Y∘X)⋅f # Lie bracket of X and Y
∂ₜ(f) = ∂ₜf

Then,

([X, Y]⋅f)(t, x) = ∂ₓf(t, x)⋅(∂ₓY(t, x)⋅X(t, x) - (∂ₓX(t, x)⋅Y(t, x)))

We thus define

(X ⅋ Y)(t, x) =  ∂ₓY(t, x)⋅X(t, x)

so that

[X, Y] = X ⅋ Y - Y ⅋ X

For the Poisson bracket, we denote by F the Hamiltonian vector field associated to f, a Hamiltonian now (I cannot write arrows). So:

F(t, x, p) = (∂ₚf(t, x, p), -∂ₓf(t, x, p)) # f(t, x, p) a non-autonomous Hamiltonian and F its Hamiltonian vector field

We define the Poisson bracket as:

{f, g} = F⋅g # the Lie derivative of g along F

and let consider for instance that we want to differentiate wrt time t -> g(t, x(t), p(t)) with ż(t) = F(t, z(t)), z=(x,p). We will write

∂ₜ(g)(t, x(t), p(t)) + {f, g}(t, x(t), p(t))
jbcaillau commented 1 year ago

@ocots One quick remark on this: IMG_2141

Regarding Lie derivatives, the idea is to differentiate $f$ along an integral curve of the nonautonomous vector field, $\dot{x}(t) = X(t, x(t))$, so

\mathrm{d}/\mathrm{d}t (f(t, x(t))) = \partial_t f(t, x(t)) + \partial_x f(t, x(t)) \cdot X(t, x(t)).

Which is coherent with adding a new time $\mathrm{d}t/\mathrm{d}s = 1$ and extending the vector field.

ocots commented 1 year ago

Yes but in practice we do not want this to be automatic. I can explain on phone.

jbcaillau commented 1 year ago

💩

ocots commented 1 year ago

I think we can close this issue. We will talk about it :-)

ocots commented 1 year ago

If we have a constraint c(t, x(t)) = 0 with a dynamics ẋ(t) = F₀(t, x(t)) + u(t) F₁(t, x(t)), then, to compute the control we will compute

dₜc(t, x(t)) = ∂ₜc(t, x(t)) + ∂ₓc(t, x(t))⋅ẋ(t) 
  = ∂ₜc(t, x(t)) + ∂ₓc(t, x(t))⋅(F₀(t, x(t)) + u(t) F₁(t, x(t))) = 0

that is

0 = ∂ₜc + F₀⋅c + u F₁⋅c

so we do not want to have (X⋅f)(t, x) = ∂ₜf(t, x) + ∂ₓf(t, x)⋅X(t, x) since otherwise we would have twice ∂ₜc.

jbcaillau commented 1 year ago

I see your point. We discuss it this Friday in Marseille. Keeping the issue open.

jbcaillau commented 1 year ago

@ocots @BaptisteCbl One more thing: looks a bit redundant to write

@Poisson { f, g }
@Lie [ X, Y ]
...

Maybe better to use a single macro (@Lie?) with different brackets / symbols for different operations:

@Lie { f, g }
@Lie [ X, Y ]
@Lie X ⋅ f
j-l-s commented 1 year ago

Coherence is the master word for me and if brackets/curly_brackets are not significient, then keep only one option:

@Poisson {H0, H1} + @Lie {F0, F1}

or

@Poisson [H0, H1] + @Lie [ F0, F1]

or

@Poisson (H0, H1) + @Lie (F0, F1)

or

@Poisson H0, H1 + @Lie F0, F1

but do not make it confusing for end users…..

(why not : @Poisson { [ (H0), (H1)] } and @Lie F0 / F1 ????

On 7 Jun 2023, at 23:20, Jean-Baptiste Caillau @.***> wrote:

@ocots @BaptisteCbl One more thing: looks a bit redundant to write @Poisson { H0, H1 } @Lie [ F0, F1 ] ... Maybe better to use a single macro @.?) with different brackets / symbols for different operations: @Lie { H0, H1 } @Lie [ F0, F1 ] @Lie F ⋅ g — Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you are subscribed to this thread.Message ID: @.>

— Jean-Luc Szpyrka

jbcaillau commented 1 year ago

Hello nightly @j-l-s ! Actually, it is exactly the point: { , } and [ , ] are distinct notations for distinct computations. The first one is for Poisson brackets of (scalar valued) functions, while the second is for Lie brackets of vector fields. (And the third notation F ⋅ g is for yet another computation...) Prefixing with a macro is just a convenient way (👍🏽 @ocots) to redefine brackets (which is not allowed otherwise). But then, only one macro @foo is enough. And since all three computations are, in some general sense, "Lie derivatives", it makes sense to call the macro @Lie (instead of @foo).