为 drake::MathematicalProgram 提供自定义渐变

Provide custom gradient to drake::MathematicalProgram

Drake 有一个接口,你可以给它一个通用函数作为约束,它可以自动设置非线性约束数学程序(只要它支持 AutoDiff)。我有一种情况,我的约束不支持 AutoDiff(约束函数进行线搜索以逼近某个函数的最大值),但我有一个约束梯度的封闭形式表达式。在我的例子中,数学计算结果很难在这个函数上找到一个点,但一旦你有了那个点,就很容易围绕它进行线性化。

我知道许多优化库允许您在可用时提供自己的分析梯度;您也可以使用 Drake 的 MathematicalProgram 来做到这一点吗?我在 MathematicalProgram class 文档中找不到它的提及。

感谢任何帮助!

这绝对是可能的,但我承认我们还没有提供让它变得漂亮的辅助函数。请让我知道 if/how 这有帮助;我将计划对其进行整理并将其添加为我们可以在 drake 中引用的示例或代码片段。

考虑以下代码:

from pydrake.all import AutoDiffXd, MathematicalProgram, Solve

prog = MathematicalProgram()
x = prog.NewContinuousVariables(1, 'x')

def cost(x):
    return (x[0]-1.)*(x[0]-1.)

def constraint(x):
    if isinstance(x[0], AutoDiffXd):
        print(x[0].value())
        print(x[0].derivatives())
    return x

cost_binding = prog.AddCost(cost, vars=x)
constraint_binding = prog.AddConstraint(
    constraint, lb=[0.], ub=[2.], vars=x)
result = Solve(prog)

当我们以这种方式向 MathematicalProgram 注册成本或约束时,我们允许它可以通过 x 作为 floatx 是一个 AutoDiffXd——它只是 Eigen's AutoDiffScalar 的包装(具有 double 类型的动态分配派生)。上面的代码片段大致向您展示了它是如何工作的——每个标量值都有一个与之相关联的(偏)导数向量。在进入该函数时,系统会向您传递 x,其中 xderivatives 设置为 dx/dx(将为 1 或零)。

你的工作是 return 一个值,称之为 y,值设置为你的 cost/constraint 的值,导数设置为 dy/dx .通常,所有这一切都会神奇地发生在你身上。但听起来你得自己做。

这是一个非常简单的代码片段,我希望它能帮助您入门:

from pydrake.all import AutoDiffXd, MathematicalProgram, Solve

prog = MathematicalProgram()
x = prog.NewContinuousVariables(1, 'x')

def cost(x):
    return (x[0]-1.)*(x[0]-1.)

def constraint(x):
    if isinstance(x[0], AutoDiffXd):
        y = AutoDiffXd(2*x[0].value(), 2*x[0].derivatives())
        return [y]
    return 2*x

cost_binding = prog.AddCost(cost, vars=x)
constraint_binding = prog.AddConstraint(
    constraint, lb=[0.], ub=[2.], vars=x)
result = Solve(prog)

让我知道?