将 le 或 ge 与标量左侧一起使用会创建未调整大小的公式数组

Using le or ge with scalar left hand side creates unsized formula array

当用 lege 创建一个带有标量左侧的公式时,返回的公式具有 .shape == (),即未确定大小的对象。这会在使用公式添加约束时导致问题。

我不确定这是否是一个错误。

prog = MathematicalProgram()
q = prog.NewContinuousVariables(1, 'q')
z = prog.NewContinuousVariables(2, 'z')
r = prog.NewContinuousVariables(rows=2, cols=3, name='r')
constraint = prog.AddConstraint(le(q, r[0,2] + 2*r[1,0])) # works
constraint2 = prog.AddConstraint(z[1] <= r[0,2] + 2*r[1,0]) # works
# constraint2 = prog.AddConstraint(le(z[1], r[0,2] + 2*r[1,0])) # fails
constraint2 = prog.AddConstraint(le([z[1]], r[0,2] + 2*r[1,0])) # works

formula = le(z[1], r[0,2] + 2*r[1,0])
print(formula.shape)
# > ()
  1. le(x,y)是另一种写法np.array(x <= y).
  2. x <= y 形成一个符号公式,它不是 iterable.
  3. 因此,np.array(x <= y) 创建了一个空数组。您可以通过检查其形状 (()) 或尝试 np.array(x <= y)[0](这会给您带来错误)来判断。
  4. 这不是 Drake-symbolic 具体的。 np.array(42) 给你一个空数组。

TL;DR

目前,您可用的解决方法:

  • 重新制定为严格 vector-valued(正如您所做的那样)
  • 传递直接对象值(使用ndarray.item
  • 将标量数组重塑/取消压缩为一维数组

也会post Drake问题。

长格式

Soonho 的 post 大体上是正确的,有一些小的更正:

  1. le(x, y)np.asarray(x) <= np.asarray(y)的另一种写法。 (参见:drake#11171, numpy.vectorize docs
  2. 虽然它确实不可迭代,但这不是重要的部分。更重要的部分是 <Formula> 对象输出被包装到一个“标量数组”中 array(<Formula>, dtype=object).
  3. 如前所述,这是一个0维数组(空形状);然而,“空数组”可能有点用词不当,因为它有数据。您可以使用 np.item()
  4. 检索内容
  5. 也正确。然而,这里的细微差别是 np.vectorize 将 return “标量数组”,而这些又不能被我们使用 pybind11.
  6. 的 Python 绑定解释。

对于第 (4) 点,我 re-ran 你在夜间 drake-20201104-bionic.tar.gz 上的示例,并收到此错误消息:

TypeError: AddConstraint(): incompatible function arguments. The following argument types are supported:
    1. (self: pydrake.solvers.mathematicalprogram.MathematicalProgram, func: function, lb: numpy.ndarray[numpy.float64[m, 1]], ub: numpy.ndarray[numpy.float64[m, 1]], vars: numpy.ndarray[object[m, 1]], description: str = '') -> drake::solvers::Binding<drake::solvers::Constraint>
    2. (self: pydrake.solvers.mathematicalprogram.MathematicalProgram, arg0: pydrake.symbolic.Expression, arg1: float, arg2: float) -> drake::solvers::Binding<drake::solvers::Constraint>
    3. (self: pydrake.solvers.mathematicalprogram.MathematicalProgram, arg0: pydrake.symbolic.Formula) -> drake::solvers::Binding<drake::solvers::Constraint>
    4. (self: pydrake.solvers.mathematicalprogram.MathematicalProgram, constraint: drake::solvers::Constraint, vars: numpy.ndarray[object[m, 1]]) -> drake::solvers::Binding<drake::solvers::Constraint>
    5. (self: pydrake.solvers.mathematicalprogram.MathematicalProgram, formulas: numpy.ndarray[object[m, n], flags.f_contiguous]) -> drake::solvers::Binding<drake::solvers::Constraint>
Invoked with: <pydrake.solvers.mathematicalprogram.MathematicalProgram object at 0x7f6eb081cdf0>, array(<Formula "(z(1) <= (2 * r(1,0) + r(0,2)))">, dtype=object)

要注意的最重要的事情是重载 (3) 可能捕获原始标量 <Formula>,而 (5) 可能捕获一维或二维数组,但两者都没有设置赶上 array(<Formula>).

这是 more-or-less 一个 pydrake and/or pybind11 问题。我现在将提交一个 Drake 问题。


FWIW 我已经 post 编辑了一个 NumPy 问题,询问 0 维数组的正确术语:
https://github.com/numpy/numpy/issues/17744