如何在 Mystic 中使用线性符号不等式创建约束?

How do I create a constraint using a linear symbolic inequality in Mystic?

我正在尝试使用 Mystic 来最小化具有线性约束的非线性函数。

作为一个简单的例子,我有以下内容:

import numpy as np
import mystic.symbolic as ms
from mystic.symbolic import generate_constraint
from mystic.symbolic import generate_solvers
from mystic.symbolic import linear_symbolic
from mystic.monitors import Monitor
from mystic.solvers import LatticeSolver
from mystic.solvers import NelderMeadSimplexSolver
from mystic.termination import CandidateRelativeTolerance as CRT

# diamond-shaped constraint
# same format as output of mystic.linear_symbolic()
basic_constraint = '''
1.0*x0 + 1.0*x1 <= 5
1.0*x0 - 1.0*x1 >= -5
1.0*x0 + 1.0*x1 >= -5
1.0*x0 - 1.0*x1 <= 5
'''[1:]

def basic_objective(x, *args):
    v1 = x[0] * x[1] / (1 + np.abs(x[0] + x[1]))
    v2 = np.min(x)
    return v1 + v2/(1+np.abs(v1))

尝试 运行 代码时,我执行以下操作:

def test_basic():
    stepmon=Monitor()
    nbins = [6,6,]
    solver = LatticeSolver(len(nbins), nbins)
    solver.SetNestedSolver(NelderMeadSimplexSolver)
    print('Generating Solvers')
    constraint_solver = generate_solvers(
        basic_constraint,
        nvars=2
    )
    print(constraint_solver)
    # HERE IS ISSUE, IF COMMENTED ISSUE BELOW
    print(constraint_solver[0](np.ones(2)))
    print('Setting Constraints')
    solver.SetConstraints(
        generate_constraint(constraint_solver)
    )
    solver.SetGenerationMonitor(stepmon)
    solver.SetTermination(CRT())
    print('Solving...')
    # ISSUE APPEARS HERE IF print(constraint_solver[0]...)
    # IS COMMENTED OUT
    solver.Solve(basic_objective)
    solution = solver.Solution()
    print(solution)
    return solution

test_basic()

当我运行上面的时候,错误发生在

print(constraint_solver[0](np.ones(2)))

或者,如果我将其注释掉,

solver.Solve(basic_objective)

唯一明显的区别是调用堆栈的大小。

我得到的错误是

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 12, in test_basic
  File "<string>", line 4, in solver_139632515562208
  File "<string>", line 1
SyntaxError: cannot assign to operator

这是 Mystic 尝试从字符串编译 Python 代码并遇到语法错误的结果,但我不知道如何解决此问题。

我是 mystic 的作者。您缺少一个关键功能,而在这种情况下不需要但通常需要的第二个功能。

如果您打印约束求解器的文档,您会发现它们的格式不正确。

>>> constraint_solver = generate_solvers(basic_constraint, nvars=2)
>>> print(constraint_solver[0].__doc__)
1.0*x[0] - 1.0*x[1] = min(5 - (_tol(5,tol,rel) * any(equal(5,[]))), 1.0*x[0] - 1.0*x[1])
>>> 

您需要在左侧隔离单个变量。因此,我们要么需要solve,要么需要simplify。对于不等式,simplify 效果更好,而对于等式 solve 通常有效。我不确定说明这一点的文档级别。无论如何,我在构建约束之前使用 simplify

>>> from mystic.symbolic import simplify
>>> constraint_solver = generate_solvers(simplify(basic_constraint), nvars=2)
>>> print(constraint_solver[0].__doc__)
x[0] = max(1.0*x[1] - 5.0 + (_tol(1.0*x[1] - 5.0,tol,rel) * any(equal(1.0*x[1] - 5.0,[]))), x[0])
>>> 
>>> print(constraint_solver[0](np.ones(2)))
[1. 1.]
>>> 

现在,您的代码按预期运行。

不过,我通常会进行另一项修改。

>>> from mystic.constraints import and_
>>> c = generate_constraint(constraint_solver, join=and_)
>>> c(np.ones(2)*5)
[0.0, 5.0]
>>> print(c.__doc__)
inner: x[0] = max(1.0*x[1] - 5.0 + (_tol(1.0*x[1] - 5.0,tol,rel) * any(equal(1.0*x[1] - 5.0,[]))), x[0])
inner: x[0] = min(1.0*x[1] + 5.0 - (_tol(1.0*x[1] + 5.0,tol,rel) * any(equal(1.0*x[1] + 5.0,[]))), x[0])
inner: x[0] = min(5.0 - 1.0*x[1] - (_tol(5.0 - 1.0*x[1],tol,rel) * any(equal(5.0 - 1.0*x[1],[]))), x[0])
inner: x[0] = max(-1.0*x[1] - 5.0 + (_tol(-1.0*x[1] - 5.0,tol,rel) * any(equal(-1.0*x[1] - 5.0,[]))), x[0])

没有 join=and_,您的代码仍然有效。不同之处在于,如果没有明确的 join 语句,则假定约束彼此 独立 ,并且可以一次解决一个问题。使用 join=and_ 强制同时求解约束,这会比较慢。也有or_等更复杂的构建约束组合,但默认是假设独立

这两点都很微妙,而且我相信,在文档中应该说明约束求解器需要符号方程需要在左侧隔离一个变量。然而,它可能并不明显,因为它经常被忽略。