Automatic differentiation: Assigning an integer ID to objects in overloaded math expressions

I am experimenting with some simple AD code implemented via overloading operators (forward mode) in dotty. I am able to declare constants and variables that represent Dual numbers. I do this as follows:

    val x5 = V(1.2)
    val c1 = C(1.0)

I can then calculate the value and first order derivative so:

    val r10 = log10(c1*x5)

Now I would like to extend this to the multivariate case i.e: expressions may use several different variables, for example:

    val r11 = log10(sqr(y2)/x5)

To do this I have to do 2 things:

  • Determine that the expression consists of n variables;
  • Assign an integer ID that is used to index a vector by that value

So in the example above:

  • n = 2
  • id(x5) = 0 and id(y2) = 1

The dual number would be:
d1 = x5 + e[1,0]
d2 = y2 + e[0,1]

If I use an ADT, I could parse the expression to determine the n and assign the IDs. However, with operator overloading this seems to be a case of chicken and egg. It does not seem to be doable.

Can anyone tell me if their is any way for me to at least make it easier for users to set the n and IDs? Note that the ID’s need to consecutive and it would be nice to be able to reuse the variables (assign new IDs in a new expression, were new here means using the = to get the result).

Any suggestions are welcome.