Search code examples
drake

Substitute symbolic variables with autodiff variables


I have some symbolic expressions stored on disk that I want to use in a non-convex program with autodiff variables. How can I substitute symbolic variables for autodiff variables?

from pydrake.all import (
    MathematicalProgram,
    SnoptSolver,
    Variable,
)

# Loaded from disk
x = Variable("x")
cost_expression = x**2

prog = MathematicalProgram()
x_vars = prog.NewContinuousVariables(1, "x")


def cost_func(vars):
    var = vars[0]
    return cost_expression.Substitute({x: var})


prog.AddCost(cost_func, vars=x_vars)

# Use Snopt with autodiff as the real problem won't be convex
solver = SnoptSolver()
result = solver.Solve(prog)

The above code gives the following error:

result: MathematicalProgramResult = solver.Solve(prog) RuntimeError: Exception while evaluating SNOPT costs and constraints: 'TypeError: Substitute(): incompatible function arguments. The following argument types are supported: 1. (self: pydrake.symbolic.Expression, var: pydrake.symbolic.Variable, e: pydrake.symbolic.Expression) -> pydrake.symbolic.Expression 2. (self: pydrake.symbolic.Expression, s: Dict[pydrake.symbolic.Variable, pydrake.symbolic.Expression]) -> pydrake.symbolic.Expression

Invoked with: <Expression "pow(x, 2)">, {Variable('x', Continuous): <AutoDiffXd 0.0 nderiv=1>}


Solution

  • Thank you, Jeremy, for the great answer! I'm writing this up here so that it is marked as completed. Substitution/ evaluation of a symbolic expression with autodiff variables is possible by converting it to an ExpressionCost.

    from pydrake.all import (
        ExpressionCost,
        MathematicalProgram,
        SnoptSolver,
        Variable,
    )
    
    # Loaded from disk
    x = Variable("x")
    cost_expression = x**2
    expression_cost = ExpressionCost(cost_expression)
    
    prog = MathematicalProgram()
    x_vars = prog.NewContinuousVariables(1, "x")
    
    
    def cost_func(vars):
        return expression_cost.Eval(vars)[0]
    
    
    prog.AddCost(cost_func, vars=x_vars)
    
    solver = SnoptSolver()
    result = solver.Solve(prog)