Constant * AdjFloat is a ufl type

Hi,

I stumbled across this today and wondered if it was intended behavior. When multiplying a Constant and an AdjFloat the result is of the type ufl.algebra.Product. In particular the result has no attribute block_variable anymore. This is different when multiplying a build in float with an AdjFloat which results in an AdjFloat.

from fenics_adjoint import Constant, AdjFloat

print(type(Constant(0.1)*AdjFloat(0.1)))
print(type(0.1*AdjFloat(0.1)))

Of course this is not a big deal but can be irritating. Minimal example:

# example.py
from fenics import (
    FiniteElement,
    FunctionSpace,
    TestFunction,
    TrialFunction,
    dx,
    grad,
    inner,
)

from fenics_adjoint import (
    Constant,
    Control,
    DirichletBC,
    Expression,
    Function,
    ReducedFunctional,
    UnitSquareMesh,
    assemble,
    minimize,
    project,
    solve,
)


def main():
    mesh = UnitSquareMesh(5, 5)
    elem = FiniteElement('CG', mesh.ufl_cell(), 1)

    space = FunctionSpace(mesh, elem)

    u = Function(space)
    v = TestFunction(space)
    y = TrialFunction(space)

    bilinear = inner(grad(y), grad(v))*dx
    rhs = u*v*dx

    y_d = project(Expression('x[0]*x[1]', element=elem), space)

    y = Function(space)
    solve(bilinear == rhs, y, DirichletBC(space, 0, 'on_boundary'))

    # this leads to an `AttibuteError: ('FloatValue' object has no attribute
    # 'block_variable')` in minimize
    # alpha = Constant(0.1)

    # however this works
    alpha = 0.1

    state_diff = assemble(inner(grad(y-y_d), grad(y-y_d))*dx)
    regularization = alpha*assemble(inner(u, u)*dx)
    cost = state_diff + regularization

    ctrl = Control(u)
    red_cost = ReducedFunctional(cost, ctrl)

    minimize(red_cost)


if __name__ == "__main__":
    main()

It is sort of intended…

The issue is that we do not know if the product should be used in a UFL form or as a float.
AdjFloats are not tracked in UFL forms, because they are not coefficients. For the same reason you can’t do:

c = 2.0
a = c * u * dx
derivative(a, c)

So now, if we cast AdjFloat * Constant to an AdjFloat, then we can’t track(differentiate) the product through UFL forms. If we convert the product to a Constant then you can’t track the individual factors (the AdjFloat and the Constant) through UFL forms. You would have to do the derivative of the product in a separate process. Now this might not be so bad, but I would like to utilize the UFL algorithmic differentiation capabilities wherever possible.

Instead I think perhaps things like: AdjFloat(Constant), or maybe even AdjFloat(AdjFloat * Constant) should be tracked so it could be used as a workaround.