Scipy Optimize constraints - scipy

Can someone please share how to properly set the constraints for Scipy Optimize?
This is for setting the sum to >=100:
def constraint1(x):
return (x[0]+x[1]-100)
How would you set it to be =100 or <=100
I just haven't seen these cases in the docs or other examples.
When I try to do the following, I get a syntax error but I've seen it work in other people examples.
def constraint2(x):
return (x[0]%=0)
This is the full example:
import numpy as np
from scipy.optimize import minimize
profit_0=50
profit_1=25
# initial guesses
n = 2
x0 = np.zeros(n)
x[0]=0
x[1]=0
def objective(x):
return -1*(x[0]*profit_0 + x[1]*profit_1)
def constraint1(x):
return (x[0]+x[1]-100)
def constraint2(x):
return (x[0]%=0)
def constraint3(x):
return (x[1]%=0)
b = (0,100)
bnds = (b, b)
con1 = {'type': 'ineq', 'fun': constraint1}
con2 = {'type': 'eq', 'fun': constraint2}
con3 = {'type': 'eq', 'fun': constraint3}
cons = ([con1,con2,con3])
solution = minimize(objective,x0,method='SLSQP',bounds=bnds,constraints=cons)#constraints=cons
x=solution.x
print (solution)

I will explain in more detail #sascha's comment.
First, let's look at the difference between inequality and equality constraints. The documentation says:
Equality constraint means that the constraint function result is to be zero whereas inequality means that it is to be non-negative.
So for the constraint that x[0] + x[1] <= 100 you can use an inequality constraint and define the constraint function as follows:
def constraint(x):
return 100 - x[0] - x[1]
which is non-negative if the condition is met.
For the condition that x[0] + x[1] == 100 you have two possibilities:
You can use two inequality constraints:
def constraint1(x):
return 100 - x[0] - x[1]
def constraint2(x):
return x[0] + x[1] - 100
con1 = {'type': 'ineq', 'fun': constraint1}
con2 = {'type': 'ineq', 'fun': constraint2}
You can use an equality constraint:
def constraint(x):
return x[0] + x[1] - 100
con = {'type': 'eq', 'fun': constraint}
You could also consider using if statements in your constraint function if that seems more intuitive to you:
def constraint(x):
return 1 if x[0] + x[1] <= 100 else 0
con = {'type': 'ineq', 'fun':constraint}
Concerning your constraint 2 and 3, note that x[0]%=0 is short for x[0] = x[0]%0. That means, it is an assignment. Trying to return an assignment gives you a syntax error.
Furthermore, you should be careful: The modulo by zero is not defined. For example 5%0 will give you an error. (Although it seems that for a numpy array x x[0]%0 only gives a warning and return 0.)
Can you explain what you want to achieve with that constraint?

Related

Root finding using a loop

I have one equation defined in the function
def fun(x, y, z, v, b):
Y = (z*(np.sign(x) * (np.abs(x))**(y-1))) - (v*np.sign(b) * (np.abs(b))**(v-1))/(1-b**v)
return Y.flatten()
that I want to solve for the value of x, given the values of Z0, SS (year 1: Z0=1.2, SS=2, ...) and different combinations of alpha and kappa, for which I am creating a grid.
Z0 = [1.2, 5, 3, 2.5, 4.2]
SS = [2, 3, 2.2, 3.5, 5]
ngrid = 10
kv = np.linspace(0.05, 2, ngrid)
av = np.linspace(1.5, 4, ngrid)
q0 = []
for z in range(len(Z0)):
zz = Z0[z]
ss = SS[z]
for i in range(ngrid):
for j in range(ngrid):
kappa = kv[i]
alpha = av[j]
res0 = root(lambda x: fun(x, alpha, zz, kappa, ss), x0=np.ones(range(ngrid)))
q0 = res0.x
print(q0)
where y = alpha; v=kappa, z = Z0; b = S.
I am getting all [], [], ....
Not sure what is going on. Thanks for your help
Before you attempt to use res0.x, check res0.success. In this case, you'll find that it is False in each case. When res0.success is False, take a look at res0.message for information about why root failed.
During development and debugging, you might also consider getting the solver working for just one set of parameter values before you embed root in three nested loops. For example, here are a few lines from an ipython session (variables were defined in previous lines, not shown):
In [37]: res0 = root(lambda x: fun(x, av[0], Z0[0], kv[0], SS[0]), x0=np.ones(range(ngrid)))
In [38]: res0.success
Out[38]: False
In [39]: res0.message
Out[39]: 'Improper input parameters were entered.'
The message suggests that something is wrong with the input parameters. You call root like this:
res0 = root(lambda x: fun(x, alpha, zz, kappa, ss), x0=np.ones(range(ngrid)))
A close look at that line shows the problem: the initial guess is np.ones(range(ngrid)):
In [41]: np.ones(range(ngrid))
Out[41]: array([], shape=(0, 1, 2, 3, 4, 5, 6, 7, 8, 9), dtype=float64)
That's not what you want! The use of range looks like a simple typo (or "thinko"). The initial guess should be
x0=np.ones(ngrid)
In ipython, we get:
In [50]: res0 = root(lambda x: fun(x, av[0], Z0[0], kv[0], SS[0]), x0=np.ones(ngrid))
In [51]: res0.success
Out[51]: True
In [52]: res0.x
Out[52]:
array([-0.37405428, -0.37405428, -0.37405428, -0.37405428, -0.37405428,
-0.37405428, -0.37405428, -0.37405428, -0.37405428, -0.37405428])
All the return values are the same (and this happens for other parameters values), which suggests that you are solving a scalar equation. A closer look at fun shows that you only use x in element-wise operations, so you are in fact solving just a scalar equation. In that case, you can use x0=1:
In [65]: res0 = root(lambda x: fun(x, av[0], Z0[0], kv[0], SS[0]), x0=1)
In [66]: res0.success
Out[66]: True
In [67]: res0.x
Out[67]: array([-0.37405428])
You could also consider using root_scalar instead of root.

Possible to set a Cp_Model constraint in terms of the sum of maxima of different variables/linear expressions?

I need to express a constraint in terms of a sum of maxima. I'm aware it's no longer a linear problem but I'm hoping that there's a way to fake or approximate it somehow:
model = cp_model.CpModel()
foo = {x: model.NewBoolVar(f"var{x}") for x in range(1, 6)}
bar = {x: model.NewBoolVar(f"var{x}") for x in range(6, 11)}
model.Add(
sum(max(k * v for k, v in variables.items()) for variables in [foo, bar]) <= 20
)
# NotImplementedError: Evaluating a BoundedLinearExpr as a Boolean value is not supported.
The error is that you can't call max():
max(k * v for k, v in foo.items())
# NotImplementedError: Evaluating a BoundedLinearExpr as a Boolean value is not supported.
Faking max() with log(sum(exp(...), ...)) doesn't work because log() fails:
log(sum(int(exp(k)) * v for k, v in foo.items()))
# TypeError: must be real number, not _SumArray
As does converting log(sum(...) into sum(prod(...)):
prod(sum(int(exp(k)) * v for k, v in variables.items()) for variables in [foo, bar])
# TypeError: Not an integer linear expression: ((((((403 * var6)) + (1096 * var7)) + (2980 * var8)) + (8103 * var9)) + (22026 * var10))
Full code listing:
from functools import reduce
from math import log, exp
import operator as op
from ortools.sat.python import cp_model
def prod(args):
return reduce(op.mul, args)
model = cp_model.CpModel()
foo = {x: model.NewBoolVar(f"var{x}") for x in range(1, 6)}
bar = {x: model.NewBoolVar(f"var{x}") for x in range(6, 11)}
model.Add(
sum(max(k * v for k, v in variables.items()) for variables in [foo, bar]) <= 20
)
# NotImplementedError: Evaluating a BoundedLinearExpr as a Boolean value is not supported.
max(k * v for k, v in foo.items())
# NotImplementedError: Evaluating a BoundedLinearExpr as a Boolean value is not supported.
log(sum(int(exp(k)) * v for k, v in foo.items()))
# TypeError: must be real number, not _SumArray
prod(sum(int(exp(k)) * v for k, v in variables.items()) for variables in [foo, bar])
# TypeError: Not an integer linear expression: ((((((403 * var6)) + (1096 * var7)) + (2980 * var8)) + (8103 * var9)) + (22026 * var10))
max() from python is interpreted before the Add() method is called. The result is unpredictable, and just wrong.
The solver is integral only, so any trick using math double functions will just not work.
just use the model.AddMaxEquality() method documented here.
In is used in many examples of the distribution, including this one.
Note that MaxArray takes an array of variables. So you will need to create intermediate variables for all terms in max equation.

How to express "implies" in ScalaCheck, say, "if an integer n * n = 0 then n = 0"?

I would like to use Scala's property-based testing tool ScalaCheck to express a property
if an integer n * n = 0 then n = 0
How can I write this property in ScalaCheck? I know for example
val myprop = forAll {(n: Int) => n + 1 - 1 = n}
But I do not know how to express "A implies B" in ScalaCheck (without reducing it to Not-A or B, which can look clumsy).
Use ==> (implication operator)
val prop = forAll { n: Int =>
(n * n == 0) ==> n == 0
}
(see their User Guide )
the catch is: in this particular example the condition is very hard to satisfy so ScalaCheck will give up after several tries (but at least it does tell you so, otherwise you get a false positive because your necessary condition was never checked). In that case you can provide a custom generator so that it will generate values that satisfy your condition.

Variable associated to "Optimization terminated successfully" in scipy.optimize.fmin_cg?

I am using scipy.optimize.fmin https://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.optimize.fmin_cg.html.
What is the variable associated to "Optimization terminated successfully"?
I need it such that I could write something like:
if "optimization not succesful" then "stop the for loop"
Thank you.
Just follow the docs.
You are interested in warnflag (as mentioned by cel in the comments), the 5th element returned, so just index
(0-indexing in python!) the result with result[4] to obtain your value.
The docs also say that some of these are only returned when called with argument full_output=True, so do this.
Simple example:
import numpy as np
args = (2, 3, 7, 8, 9, 10) # parameter values
def f(x, *args):
u, v = x
a, b, c, d, e, f = args
return a*u**2 + b*u*v + c*v**2 + d*u + e*v + f
def gradf(x, *args):
u, v = x
a, b, c, d, e, f = args
gu = 2*a*u + b*v + d # u-component of the gradient
gv = b*u + 2*c*v + e # v-component of the gradient
return np.asarray((gu, gv))
x0 = np.asarray((0, 0)) # Initial guess.
from scipy import optimize
res1 = optimize.fmin_cg(f, x0, fprime=gradf, args=args, full_output=True) # full_output !!!
print(res1[4]) # index 4 !!!

Express X as the sum of the the Nth power of unique natural numbers

I have recently been playing around on HackerRank in my down time, and am having some trouble solving this problem: https://www.hackerrank.com/challenges/functional-programming-the-sums-of-powers efficiently.
Problem statement: Given two integers X and N, find the number of ways to express X as a sum of powers of N of unique natural numbers.
Example: X = 10, N = 2
There is only one way get 10 using powers of 2 below 10, and that is 1^2 + 3^2
My Approach
I know that there probably exists a nice, elegant recurrence for this problem; but unfortunately I couldn't find one, so I started thinking about other approaches. What I decided on what that I would gather a range of numbers from [1,Z] where Z is the largest number less than X when raised to the power of N. So for the example above, I only consider [1,2,3] because 4^2 > 10 and therefore can't be a part of (positive) numbers that sum to 10. After gathering this range of numbers I raised them all to the power N then found the permutations of all subsets of this list. So for [1,2,3] I found [[1],[4],[9],[1,4],[1,9],[4,9],[1,4,9]], not a trivial series of operations for large initial ranges of numbers (my solution timed out on the final two hackerrank tests). The final step was to count the sublists that summed to X.
Solution
object Solution {
def numberOfWays(X : Int, N : Int) : Int = {
def candidates(num : Int) : List[List[Int]] = {
if( Math.pow(num, N).toInt > X )
List.range(1, num).map(
l => Math.pow(l, N).toInt
).toSet[Int].subsets.map(_.toList).toList
else
candidates(num+1)
}
candidates(1).count(l => l.sum == X)
}
def main(args: Array[String]) {
println(numberOfWays(readInt(),readInt()))
}
}
Has anyone encountered this problem before? If so, are there more elegant solutions?
After you build your list of squares you are left with what I would consider a kind of Partition Problem called the Subset Sum Problem. This is an old NP-Complete problem. So the answer to your first question is "Yes", and the answer to the second is given in the links.
This can be thought of as a dynamic programming problem. I still reason about Dynamic Programming problems imperatively, because that was how I was taught, but this can probably be made functional.
A. Make an array A of length X with type parameter Integer.
B. Iterate over i from 1 to Nth root of X. For all i, set A[i^N - 1] = 1.
C. Iterate over j from 0 until X. In an inner loop, iterate over k from 0 to (X + 1) / 2.
A[j] += A[k] * A[x - k]
D. A[X - 1]
This can be made slightly more efficient by keeping track of which indices are non-trivial, but not that much more efficient.
def numberOfWays(X: Int, N: Int): Int = {
def powerSumHelper(sum: Int, maximum: Int): Int = sum match {
case x if x < 1 => 0
case _ => {
val limit = scala.math.min(maximum, scala.math.floor(scala.math.pow(sum, 1.0 / N)).toInt)
(limit to 1 by -1).map(x => {
val y = scala.math.pow(x, N).toInt
if (y == sum) 1 else powerSumHelper(sum - y, x - 1)
}).sum
}
}
powerSumHelper(X, Integer.MAX_VALUE)
}