I am trying to use Mystic to minimize a nonlinear function with linear constraints.

As a simple example, I have the following:

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))

When trying to run the code, I do the following:

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()

When I run the above, the error occurs at

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

or, if I comment it out,

solver.Solve(basic_objective)

The only noticeable difference is the size of the call stack.

The error I get is

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

This is a result of Mystic trying to compile Python code from a string and encountering a syntax error, but I do not know how to fix this issue.

## Answer

I’m the `mystic`

author. You are missing one key function, and a second that is not needed in this case but often is.

If you print the doc for your constraint solvers, you’ll see that they are not formed well.

>>> 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]) >>>

You need to isolate a single variable on the left-hand side. Hence, we either need to `solve`

or `simplify`

. For inequalities, `simplify`

works better, and for equalities `solve`

generally works. I am not sure the level of documentation that states that. Anyway, I use `simplify`

before building the constraints.

>>> 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.] >>>

Now, your code works as expected.

However, I’d generally make one other modification.

>>> 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])

Without the `join=and_`

, your code still works. The difference is that without an explicit `join`

statement, it’s assumed the constraints are **independent** of each other, and can be solved one at a time. Using `join=and_`

forces the constraints to be solved simultaneously, which is slower. There’s also `or_`

and other more complex combinations in building constraints, but the default is to assume independence.

Both points are subtle, and, I believe, in the documentation it should state that the constraints solvers need the symbolic equations need to have a single variable isolated on the left-hand side. However, it’s probably not obvious as that’s often missed.