pyomo icon indicating copy to clipboard operation
pyomo copied to clipboard

Extract Jacobian for equality constraints then embed symbolic expressions in constraints

Open adowling2 opened this issue 9 months ago • 6 comments

Summary

I have a square Pyomo model with equality constraints $h(y,p) = 0$. I want to compute $\nabla_y h$ and $\nabla_p h$ for this model and then embed those expressions into Pyomo constraints. $h(.,.)$ is nonlinear, for the Jacobian will not be constant.

#3561 sparked my interest in this.

Rationale

This feature would be handy for Pyomo.DoE and uncertainty quantification (UQ) more broadly. In the current Pyomo.DoE/ParmEst abstraction, $h(.,.)$ is the experiment model. $y$ are the annotated measurements and $p$ are the annotated parameters. The model is square when the measurement decisions $x$ (not shown) and parameters $p$ are fixed.

If we can compute the Jacobians with automatic differentiation (AD), we can add the constraint:

$\nabla_p h = - \nabla_y h \nabla_p y$

Notice that $\nabla_p y$ is the sensitivity matrix $Q$ we need for Pyomo.DoE. In Pyomo.DoE, we currently use finite difference to approximate $Q$. Performing automatic differentiation on $h(.,.)$ would allow us to have a much more compact Pyomo.DoE formulation.

Description

See above.

Could you point me to examples of performing AD on Pyomo constraints and then using those symbolic AD results to construct new Pyomo constraints/expressions? I think PyNumero interfaces with the AMPL AD, but returns the derivatives evaluated at a current point. I was the symbolic derivates. (Please correct me if this understanding of PyNumero is incorrect.)

Additional information

See above.

adowling2 avatar Apr 15 '25 19:04 adowling2

This should all be possible. We can compute symbolic derivatives with respect to both variables and parameters:

In [1]: import pyomo.environ as pe
   ...: from pyomo.core.expr.calculus.diff_with_pyomo import reverse_sd
   ...: m = pe.ConcreteModel()
   ...: m.x = pe.Var()
   ...: m.p = pe.Param(initialize=7, mutable=True)
   ...: e = m.x**2 + pe.log(m.p)

In [2]: for k, v in reverse_sd(e).items():
   ...:     print(f'derivative with respect to {str(k)} is {str(v)}')
   ...:
derivative with respect to x is 2*x
derivative with respect to 2 is 0
derivative with respect to x**2 is 1
derivative with respect to p is 1/p
derivative with respect to log(p) is 1
derivative with respect to x**2 + log(p) is 1

Let me know if I am missing something.

michaelbynum avatar Apr 15 '25 21:04 michaelbynum

@michaelbynum Thank you. Is there an easy way to take a constraint and compute its symbolic derivative relative to a variable? I then want to add the symbolic expression as another constraint.

I am working in a notebook here: https://github.com/dowlinglab/pyomo-doe/pull/8

adowling2 avatar Apr 16 '25 13:04 adowling2

For the example in the linked repo, I have a model with equality constraints $h(x)=0$. As a starting point, I want to assemble the Jacobian matrix $\nabla_x h$ symbolically.

adowling2 avatar Apr 16 '25 14:04 adowling2

Just in case anyone else is tracking this issue, @adowling2's notebook has a nice example of this.

michaelbynum avatar Apr 16 '25 16:04 michaelbynum

The example is nice thank you to @michaelbynum!

adowling2 avatar Apr 16 '25 20:04 adowling2

I started to implement these ideas in Pyomo.DoE! See https://github.com/adowling2/pyomo/pull/7

adowling2 avatar Jun 04 '25 13:06 adowling2