How to use min & max in objective function in pyomo - python

I am very new to Pyomo, working on a use case where my objective function coefficient is dynamic & needs a min-max function.
Objective function = Max( sum (P * UC) - sum ( P - min(P)) * UC
where P is variable needs to be optimized and UC is function which is derived value based on some calculation.
I have few doubts
how to use min or max function in objective function, I have tried np.min or calling function but it gives error since function has if else condition
I have tried multiple things but none seems to be working. If someone can help me with dummy code that will be great.
Thanks in Advance.

Min could be implemented by defining a new variable min_P, which needs to be smaller than any of the P, expressed by constraints:
min_P <= P[i] for all i
This will make sure, that min_P is not larger than the smallest of the P. Then you can just use min_P in your objective function. I assume you know how to define constraints like this. This might result in an unbound variable problem, depending on how exactly you are optimizing, but this should put you on the right track.
The max case is analogous, if you define another value for the expression sum (P * UC) - sum ( P - min(P)).
It is not clear whether UC is a parameter or a variable itself (calculated in another constraint). In the latter case, the whole problem will be highly nonlinear and should be reconsidered.
I do not understand your AbstractModel vs ConcreteModel question. If you have the data available, use a ConcreteModel. Apart from that, see here.

Related

Compare decision variables to floating values

I'm currently working on a trajectory optimization problem that involves binary actuators. In order to avoid solving an MINLP I do not simply optimize over the states and control inputs but instead, assume that each of the binary actuators alternates between the states "on" and "off" and optimize over the duration of those intervals. I will call the array containing the decision variable h (an N by 2 matrix in the particular case below).
A minimal example using a double integrator that has two control inputs that enact a positive or negative force on the system respectively would be:
Here I model the state trajectory as some train of 3rd order polynomial.
I particularly do not want to merge these actuators into one with the states -1,0,1 since the more general system I'd like to apply this to also has more binary actuators. I add some additional constraints such as connecting the polynomials continuously and differentiably; enforce that the sum of all intervals is equal to the desired final time; enforce initial and final state constraints and finally enforce the dynamics of the system.
My initial idea was to then enforce the dynamics at constant intervals, i.e.:
However, the issue here is that any of the actuators could be in any arbitrary interval for some time t. Since the intervals can shrink to duration zero one actuator might be in the last interval while the other one remains in the first. I.e. the value of a decision variable (time duration) changes which decision variables are dependent on each other. This is more or less manifested in drake by the fact that I cannot do a comparison such as Tau < t if Tau is a drake expression and t is some number. The code snippet is:
# Enforce dynamics at the end of each control interval
for t in np.arange(0, Tf, dt_dyn):
# Find the index of the interval that is active for each actuator
t_ctrl = np.cumsum(h, axis=0)
intervals = (t_ctrl < t)
idxs = np.sum(intervals, axis=0)
# If the idx is even the actuator is off, otherwise its on
prog.AddConstraint(eq(qdd(q_a, t, dt_state),
continuous_dynamics(q(q_a, t, dt_state),
qd(q_a, t, dt_state),
[idxs[0] % 2, idxs[1] % 2])))
and the resulting error message:
Traceback (most recent call last):
File "test.py", line 92, in <module>
intervals = (t_ctrl < t)
RuntimeError: You should not call `__bool__` / `__nonzero__` on `Formula`. If you are trying to make a map with `Variable`, `Expression`, or `Polynomial` as keys (and then access the map in Python), please use pydrake.common.containers.EqualToDict`.
In the end, my question is more of a conceptual than technical nature: Does drake support this dependence of the "dependence of decision variables on the values" in some other way? Or is there a different way I can transcribe my problem to avoid the ambiguity in which interval my actuators are for some given time?
I've also linked to the overall script that implements the minimal example here
The immediate problem is that intervals = (t_ctrl < t) is a vector of dtype Formula, not a vector of dtype Variable(type=BINARY), so you can't actually sum it up. To do an arithmetic sum, you'd need to change that line to an np.vectorize-wrapped function that calls something like if_then_else(t_argument < t_constant, 0.0, 1.0) in order to have it be an Expression-valued vector, at which which would be sum-able.
That won't actually help you, though, since you cannot do % (modular) arithmetic on symbolic expressions anyway, so the % 2.0 == 0.0 stuff will raise an exception once you make it that far.
I suspect that you'll need a different approach to encoding the problem into variables, but unfortunately an answer there is beyond my skill level at the moment.

Problem with roots of a non-linear equation

I have a hyperbolic function and i need to find the 0 of it. I have tried various classical methods (bisection, newton and so on).
Second derivatives are continuous but not accessible analytically, so i have to exclude methods using them.
For the purpose of my application Newton method is the only one providing sufficient speed but it's relatively unstable if I'm not close enough to the actual zero. Here is a simple screenshot:
The zero is somewhere around 0.05. and since the function diverges at 0, if i take a initial guess value greater then the minimum location of a certain extent, then i obviously have problems with the asymptote.
Is there a more stable method in this case that would eventually offer speeds comparable to Newton?
I also thought of transforming the function in an equivalent better function with the same zero and only then applying Newton but I don't really know which transformations I can do.
Any help would be appreciated.
Dekker's or Brent's method should be almost as fast as Newton. If you want something simple to implement yourself, the Illinois variant of the regula-falsi method is also reasonably fast. These are all bracketing methods, so should not leave the domain if the initial interval is inside the domain.
def illinois(f,a,b,tol=1e-8):
'''regula falsi resp. false postion method with
the Illinois anti-stalling variation'''
fa = f(a)
fb = f(b)
if abs(fa)<abs(fb): a,fa,b,fb = b,fb,a,fa
while(np.abs(b-a)>tol):
c = (a*fb-b*fa)/(fb-fa)
fc = f(c)
if fa*fc < 0:
fa *= 0.5
else:
a, fa = b, fb
b, fb = c, fc
return b, fb
How about using log(x) instead of x?
For your case, #sams-studio's answer might work, and I would try that first. In a similar situation - also in multi-variate context - I used Newton-homotopy methods.
Basically, you limit the Newton step until the absolute value of y is descending.
The cheapest way to implement is that you half the Newton step if y increases from the last step. After a few steps, you're back at Newton with full second order convergence.
Disclamer: If you can bound your solution (you know a maximal x), the answer from #Lutz Lehmann would also be my first choice.

Writing a function to compute a quantity in python based on a math problem

Write a function to compute the quantity
F(n) = n^2 Σ i=1 (i^3)
Read the problem as n squared over Sigma, with i = 1 under the sigma and I cubed at the end of the function.
I am not sure how to approach this idea. I tried setting up a function but I do not know how to use a function in Python to compute the problem we were given.
As mentioned above, I am sorry, but I do not know how to approach this problem.
I suppose the expected output here would be some quantity but because I haven't been able to make much progress, I have no clue what to expect exactly. To give more background, I understand how functions work but do not know how to approach this type of problem. Any help/guidance in writing this code would be greatly appreciated.
With a list comprehension:
Use the built-in functions, sum and range
def my_sigma(n_start: int, n_end: int) -> int:
return sum([i**3 for i in range(n_start, (n_end**2) + 1)])
# usage
print(my_sigma(1, 3))
>>> 2025
You can use the Math library to take the powers, and use a for loop for the sigma.
I think this would give you an idea,
for i in range (a , int(math.pow(n, 2))):
list_1.append(int(math.pow(i, 3)))
You can just put this inside a function with two variables a and n a representing the i in the sigma and n representing the n in the sigma.
You can use the sum function for summing up all the elements in the list if that is what you want.

python polynomial fit with some coefficients being fixed, order should be a parameter, need to create list of variables?

I need some help writing a pretty simple code (at least in pseudo code):
I want fit data using a polynomial of order n, where n is a parameter and should be changable. On top of that I would like to always keep the first three coefficients fixed to be zero. So I need something like
order = 5
def poly(x,c0=0,c1=0,c2=0,c3,c4,c5):
return numpy.polynomial.polynomial.polyval(x, [c0,c1,c2,c3,c4,c5], tensor=False)
popt, pcov = scipy.optimize.curve_fit(poly,x,y)
So problems I can not sove atm is:
How do I create a polynomial function with n number of coefficents? I basicly need to create a list of variables of length n.
If that is solved than we could put c0 to c2 to 0.
I hope I was able to make myself clear, if not please help me to refine my question.
You currently do not keep the first 3 coefficient fixed to 0, you just give them a default value.
Arbitrary argument lists seem to be what you are looking for:
def poly(x,*args):
return numpy.polynomial.polynomial.polyval(x, [0,0,0] + list(args), tensor=False)
If the number of arguments MUST be of fixed length (for instance n), you can check len(args) and raise an error if necessary.
Calling poly(x,a,b,c) now returns the polynomial function with the coefficients [0,0,0,a,b,c]
You can find more information in Python's documentation: https://docs.python.org/3/tutorial/controlflow.html#more-on-defining-functions

scipy.optimize.minimize with matrix constraints

I am new to scipy.optimize module. I am using its minimize function trying to find a x to minimize a multivariate function, which takes matrix input but return a scalar value. I have one equality constraint and one inequality constraint, both taking vector input and return vector values. Particularly, here is the list of constraints:
sum(x) = 1 ;
AST + np.log2(x) >= 0
where AST is just a parameter. I defined my constraint functions as below:
For equality constraint: lambda x: sum(x) - 1
For inequality constraint:
def asset_cons(x):
#global AST
if np.logical_and.reduce( (AST + np.log2(x)) >= 0):
return 0.01
else:
return -1
Then I call
cons = ({'type':'eq', 'fun': lambda x: sum(x) - 1},
{'type':'ineq', 'fun': asset_cons})
res = optimize.minize(test_obj, [0.2, 0.8], constraints = cons)
But I still got error complaining my constraint function. Is it allowed to return vector value for constraint function or I have to return a scalar in order to use this minimize function?
Could anyone help me to see if the way I specify the constraints has any problems?
In principle this does not look that wrong at all. However, it is a bit difficult to say without seeing something about test_obj and the actual error. Does it throw an exception (which hints at a programming error) or complain about convergence (which hints at a mathematical challenge)?
You have the basic idea right; you need to have a function accepting an input vector with N elements and returning the value to be minimized. Your boundary conditions should also accept the same input vector and return a single scalar as their output.
To my eye there is something wrong with your boundary conditions. The first one (sum(x) - 1) is fine, but the second one is mathematically challenging, as you have defined it as a stepwise function. Many optimization algorithms want to have continuous functions with preferable quite smooth behaviour. (I do not know if the algorithms used by this function handle stepwise functions well, so this is just a guess.
If the above holds true, you might make things easier by, for example:
np.amin(AST + np.log2(x))
The function will be non-negative if all AST + log2(x[n]) >= 0. (It is still not extremely smooth, but if that is a problem it is easy to improve.) And now it'll also fit into one lambda.
If you have difficulties in convergence, you should probably try both COBYLA and SLSQP, unless you already know that one of them is better for your problem.

Categories