Opened 3 years ago

Closed 3 years ago

# Tangent vectors should act as derivations on scalar fields

Reported by: Owned by: egourgoulhon major sage-8.8 geometry vector, derivation tscrim Eric Gourgoulhon Travis Scrimshaw N/A 4c0abd7 4c0abd75065fae7820988a6eb8c2a0ebcb3091f9

### Description

In Sage 8.7, we have

```sage: M = Manifold(2, 'M')
sage: X.<x,y> = M.chart()
sage: p = M((2,-1), name='p')
sage: TpM = M.tangent_space(p)
sage: v = TpM((-2, 3), name='v'); v
Tangent vector v at Point p on the 2-dimensional differentiable manifold M
sage: f = M.scalar_field(x*y^2, name='f')
sage: v(f)
Traceback (most recent call last):
...
TypeError: the argument no. 1 must be a linear form
```

Note that this works for vector fields:

```sage: w = M.vector_field(name='w')
sage: w[:] = -y, x
sage: w.display()
w = -y d/dx + x d/dy
sage: w(f)
Scalar field w(f) on the 2-dimensional differentiable manifold M
sage: w(f).display()
w(f): M --> R
(x, y) |--> 2*x^2*y - y^3
```

This issue has been reported in this ask.sagemath question.

### comment:1 Changed 3 years ago by egourgoulhon

• Branch set to public/manifolds/vector_derivation-27856
• Commit set to 50bc6da98b97fe2104f670c0cc7412211f87be7f

New commits:

 ​50bc6da `Add action of tangent vectors on scalar fields`

### comment:2 Changed 3 years ago by egourgoulhon

• Status changed from new to needs_review

### comment:3 follow-up: ↓ 4 Changed 3 years ago by tscrim

A good general rule that you should follow is to not overwrite `__call__`. Instead, the typical thing to do is implement an `_act_on_` (or `_acted_upon_`), and let the coercion framework handle the dispatching.

### comment:4 in reply to: ↑ 3 Changed 3 years ago by egourgoulhon

A good general rule that you should follow is to not overwrite `__call__`. Instead, the typical thing to do is implement an `_act_on_` (or `_acted_upon_`), and let the coercion framework handle the dispatching.

I am a little bit puzzled by this: looking at lines 1154-1184 of `src/sage/structure/coerce.pyx`, I have the impression that `_act_on_` is used for actions denoted by `__mul__`, not by `__call__`. This seems confirmed from the doctest examples one can get from `grep -r "def _act_on_" src/sage`. Now, in the current setting, we do want to write `v(f)` for the action of a tangent vector `v` on a scalar function `f`, not `v*f`. For instance, we can form the derivation law that looks very much the textbook formula (`p` being the point at which `v` is defined):

```v(f*g) == v(f)*g(p) + f(p)*v(g)
```

There is no redefinition of `__call__` in `src/sage/structure/element.pyx`, contrary to `__add__`, `__mul__`, etc., which leads one to think that `__call__` is not delt via the coercion framework. Supporting this, we can note that overwriting `__call__` is much used in Sage library: `grep -r "def __call__" src/sage | wc -l` returns 496 instances (on the contrary, `grep -r "def _act_on_" src/sage | wc -l` returns only 16 instances). Am I missing something?

Last edited 3 years ago by egourgoulhon (previous) (diff)

### comment:5 follow-up: ↓ 7 Changed 3 years ago by tscrim

Ah, I see. I saw act in the ticket and was thinking it should behave like a normal action (and be written with a binary operation such as multiplication). So sorry about that noise there. I guess this is fine since it is done on an element and not a parent. (As a side note, it is actually `__call__` that starts the dispatch to the coercion framework, not something that is dealt out from it.)

Only other thing you need to address is changing `EXAMPLES::` -> `EXAMPLES:` to get a positive review.

### comment:6 Changed 3 years ago by git

• Commit changed from 50bc6da98b97fe2104f670c0cc7412211f87be7f to 4c0abd75065fae7820988a6eb8c2a0ebcb3091f9

Branch pushed to git repo; I updated commit sha1. New commits:

 ​4c0abd7 `Correct EXAMPLES statement in tangent_vector`

### comment:7 in reply to: ↑ 5 ; follow-up: ↓ 8 Changed 3 years ago by egourgoulhon

Ah, I see. I saw act in the ticket and was thinking it should behave like a normal action (and be written with a binary operation such as multiplication). So sorry about that noise there.

No problem. Actually I should have used "behave" instead of "act" to avoid any confusion (there is indeed no group action here).

I guess this is fine since it is done on an element and not a parent.

(As a side note, it is actually `__call__` that starts the dispatch to the coercion framework, not >something that is dealt out from it.)

For my own instruction, can you tell by which magic this is done (given that `__call__` is not redefined in the base class `Element`)?

Only other thing you need to address is changing `EXAMPLES::` -> `EXAMPLES:` to get a positive review.

Done in the above commit.

### comment:8 in reply to: ↑ 7 ; follow-up: ↓ 10 Changed 3 years ago by tscrim

• Authors set to Eric Gourgoulhon
• Reviewers set to Travis Scrimshaw

I guess this is fine since it is done on an element and not a parent.

(As a side note, it is actually `__call__` that starts the dispatch to the coercion framework, not >something that is dealt out from it.)

For my own instruction, can you tell by which magic this is done (given that `__call__` is not redefined in the base class `Element`)?

It is `Parent.__call__` that starts the process off. However, you can explicit invoke the coercion framework by importing the `coercion_model` within your own class. There are also things like `@coerce_binop` as helpers too.

Only other thing you need to address is changing `EXAMPLES::` -> `EXAMPLES:` to get a positive review.

Done in the above commit.

Thanks, LGTM.

### comment:9 Changed 3 years ago by tscrim

• Status changed from needs_review to positive_review

### comment:10 in reply to: ↑ 8 Changed 3 years ago by egourgoulhon

It is `Parent.__call__` that starts the process off. However, you can explicit invoke the coercion framework by importing the `coercion_model` within your own class. There are also things like `@coerce_binop` as helpers too.