ufl icon indicating copy to clipboard operation
ufl copied to clipboard

Dualspace

Open dham opened this issue 3 years ago • 3 comments

This PR implements Dual function spaces, cofunctions in dual function spaces, arguments, and all the consequential objects needed to support dual operations and operators in UFL. This is documented in this thesis: https://drive.google.com/file/d/1hH_ntqZYThicpkStVwkBR-CrQ185bb95/view

It is intended to be backwards compatible so packages which don't currently use dual spaces will never see any dual objects.

This is an unfortunately big diff, but is claimed to be the minimal change which implements a closed set of functionality. The interpolation operator and external operators use this to provide actual functionality. They will follow in a subsequent PR.

dham avatar Feb 01 '22 14:02 dham

Thanks for the contribution. I had a quick look.

Why is it needed to distinguish primal and dual Coefficients with a new name "Cofunction"? I'd say

V_dual = V.dual()
v_dual = Coefficient(V_dual)

(and the same for Argument) should have the same meaning. No need for that extra code which check if you ask for "cofunction" on primal or dual space. One can add the parent class runtime based on if FS is primal or dual. Also the word cofunction seems to be reserved a different meaning, https://en.wikipedia.org/wiki/Cofunction.

I like you've added BaseForm for a linear functional. The old Form should not have been reserved for "integral" forms, but that would require a larger braking change...

Can you explain why is an extra class FormSum required to handle the sum of BaseForms?

michalhabera avatar Feb 18 '22 11:02 michalhabera

Also the word cofunction seems to be reserved a different meaning, https://en.wikipedia.org/wiki/Cofunction.

Here it's being used to refer to the category theory meaning (hence the link at the top of the wikipedia article to https://en.wikipedia.org/wiki/Dual_(category_theory). But googling for "Cofunction" definitely gives you results that are all about angles!

ReubenHill avatar Feb 18 '22 12:02 ReubenHill

Sorry for taking a while to get back, I'm catching up after being on strike.

The reason why dual coefficients and dual arguments need to be different types to primal ones is that they are fundamentally different objects with different algebraic properties. Cofunctions and Coarguments are FormBase objects they can be used where other 1-forms could be used, and they can't be used where UFL.expr is needed. For example, suppose u is an Argument and v is a Cofunction. The following makes mathematical sense and can be supported in code:

u*dx + v

However, v*dx does not make sense and should be an error. Similarly, if w is a Coefficient then:

u*dx + w

must be an error. The clean way to achieve this is through different types. What complicates things in this case is that the inheritance relationships work in two ways. Coefficient and Cofunction are both known values in vector spaces (primal and dual spaces respectively). Similarly, Argument and Coargument are both unknown values in vector spaces. The class inheritance relations reflect the commonality and differences between these cases cleanly. The alternative would be an enormous number of hand-coded dispatches on the type of the underlying function space. We should make the OO features of Python work for us and not fight against them.

On the name Cofunction, I am open to alternatives but I haven't heard a good one yet. Sure, we're overloading a term which is used in a different bit of maths, but the category-theoretic use of the prefix "co-" does make sense. The strictly UFL name would be Cocoefficient, however the confusion that that would cause is easily predictable.

The reason that we need FormSum is the same as the reason that we need Action and Adjoint. Every operation which is legal on a FormBase either has to evaluate eagerly or has to return a symbolic expression which can be evaluated at assembly time. Since taking the action, adjoint or a linear combination of FormBase objects can be a large numerical operation, it needs to be delayed to assembly time. It should be noted that FormSum is quite similar to Form in this respect: Form stores a sum of integrals. As you say, if we were doing this from scratch then we might implement and name Form differently. I think the design we have here is a good balance of keeping things as clean as we can without breaking what we already have.

dham avatar Feb 24 '22 21:02 dham