Goal
The goal is to minimize an output variable of a computer code whose function is unknown, we will call it F. There are 25 input variables, xij, and 5 output variables, yk.
xij, where i ∈ [1,5] and j ∈ [1,5]
yk, where k ∈ [1,5]
F(x) = y
Inputs
Each input variable, xij, represents a position in a matrix-like pattern and holds a categorical value, el. There are 50 different categorical values to choose from.
el, where l ∈ [1,50]
For example, one possible assignation of values to input variables would be:
x1,1=e1
x1,2=e2
⋯
x5,5=e25
The last 25 values [e26, e50] will be unassigned, no problem.
Moreover, there are restrictions on all input variables. Each input variable, xij, has a restriction on the value it can hold, el. For example:
xij ∈ {em, …, eq}
Imagine that the above assignation (xij = e(i-1)5+j) fulfills these restrictions. That is not a problem.
Outputs
Once all input variables are assigned and feed into the code, the code spits out 5 output variables, yk.
yk, where k ∈ [1,5]
I want to minimize y1, but there are restrictions on all output variables.
yk < yk,lim, where k ∈ [1,5]
Objective function
Hence, I can obtain an objective function as follows:
Where:
ωk = 1 if yk > yk,lim ; 0 otherwise
The last term in the right hand side of the O.F. is a penalization when yk restriction is not fulfilled. Each ωk has value 1 if the corresponding restriction is not fulfilled, 0 otherwise. The normalization of each yk is done so all penalizations and the main output, y1, are on the same range, that is around 1.0.
Question
Do you think this can be done? That is, can I minimize the O.F.? What method or algorithm do you recommend?
Please, take into account the following.
All input variables are categorical
As far as I understood, MINPL is recommended for categorical optimization
Use of any Python library (scipy, mystic, openopt, pyomo…) is preferred
Any other suggestions or recommendations that I did not came up with are also welcome.
Thank you.
Related
I am trying to declare a constraint in Pyomo where one parameter would be a list instead of a scalar and then build the constraint by providing a set of the right dimension but it seems that Pyomo does the Cartesian product of every set and deduces the number of inputs (which are then considered as scalars).
Below a dummy example of what I want to achieve:
model.inputs = RangeSet(0,1)
model.x = model.inputs*model.inputs
model.p = Var()
def constraint_rule(model,x,i):
return x[i] > model.p
model.constraint = Constraint(model.x,model.inputs,rule=constraint_rule)
To be more precise on what I want to achieve. My constraint is of the form:
f(x_0,x_1,i) > p
And I'd like to input x as a vector instead of inputting separately x_0 and x_1 (or more if I have more x_i). So I want to input a list of lists for the first parameter and a iterator as the second parameter which could specify which element of the list I want.
I can of course decompose the list x of lenght n with n scalars x[i] but because I want to keep changing the size of the inputs, I wanted to only change model.x and hope it would automatically scale.
Below the full mathematical problem (I don't have enough reputation to put an image, sorry about that):
Tr(MixiNx) > p
Tr(Nx) = 1
Mi0 + Mi1 = Id
Mi0, Mi1 and Nx SDP
Here the Ms and Ns are 2x2 matrices.
We have 4 N for bitstrings of lenght 2 and 2 matrices M per value of i (then xi is either 0 or 1).
Also x specifies the bitstring (here we have only x_0 and x_1) and i specifies which bit (for instance for i=0, we want the value x_0 ie the first bit of x). But i could be larger than the number of the number of bits in x (for instance we could set that for i=2, we want the value x_0 xor x_1 ie the parity of the bits). So I wanted to encode the 1sr constraint such it receives a bitstring x and a value i which could specify which information I want about that bitstring.
I hope that's clearer.
I am going to define a set of dynamic variables like X1, X2,..., Xd (which d = dimension is the input and is not a fixed number) and allocate this unknowns to a C(1,d) vector. It is supposed that the matrix multiplication of this (1,d) vector of unknowns in a B(d,d) matrix (all elements are known in B) gives me 'd' equations that I can solve for those 'd' unknown variables. Simply speaking, 'd' equations, 'd' unknowns.
In Matlab, there was a kind of solution like ['X' num2str(i)] to define the variables dynamically, but I could not find any way in python.
I would think there is a way to define dynamic variables, so I could write:
C = np.ones((d,1))
C = (1/d)* C
for i in range (0,d):
C[i] = C[i] * X(i)
for j in range (0,d):
for i in range (0,d):
eq(j) = sum(C[i]*B[i][j])
But as it turns out, such a way to define dynamic variables is not allowed and makes problems in producing X[i]s and allocating them to C[i]s as well as in numbering the equations eq[j]s.
Thanks for your suggestions, but they are not applicable in my question.
What you have referred me to are all for the case that I want to assign a beginning value to these variables. Actually, these are functions which their type should float because they are supposed to be allowed for multiplying to other numbers but still should not have a value. I hope you understand what I mean. For example think we have two equations (x+y-3=0) and (x+3y-2=0). You can not allocate some initial value to the defined variables, because it scrows up your set off equations.
Here I need a set of dynamically named functions based on my input 'd' which defines how many of these equations will be built. As you can see in the last set of nested for(s), the 'd' specifies the number of equation which will be built. I CAN NOT allocate a number to those space holders while they should be known as floats to be able to multiply and add them to numbers in my matrices.
And I need d number of these so-called variables. That is why I have written it should be produced during the runtime.
Please don't superscribe this post directly as duplicate.
I want that a design variable assumes only specified values during optimization process.
For example:
Let x be the variable which can assume only specific value, e.g.:
x = [0.1,0.5,1.0,1.7,2.3]
How can be written in python using pyomo (if it's possible)?
I hope I was clear.
You have to do this with integer variables. For example, if there are N possible values of x, then let x[n] = 1 if x equals the nth possible value, and 0 otherwise. Any time you have an x in your original model, replace it with
sum {n=1,...,N} v[n] * x[n]
where v[n] is the nth possible value. Finally, add a constraint that says:
sum {n=1,...,N} x[n] == 1
I'm not writing these in Pyomo syntax, but this is a general modeling approach that is the same no matter what modeling language/package you use.
Assume we have a function with unknown formula, given few inputs and results of this function, how can we get the function's formula.
For example we have inputs x and y and result r in format (x,y,r)
[ (2,4,8) , (3,6,18) ]
And the desired function can be
f(x,y) = x * y
As you post the question, the problem is too generic. If you want to find any formula mapping the given inputs to the given result, there are simply too many possible formulas. In order to make sense of this, you need to somehow restrict the set of functions to consider. For example you could say that you're only interested in polynomial solutions, i.e. where
r = sum a_ij * x^i * y^j for i from 0 to n and j from 0 to n - i
then you have a system of equations, with the a_ij as parameters to solve for. The higher the degree n the more such parameters you'd have to find, so the more input-output combinations you'd need to know. Variations of this use rational functions (so you divide by another polynomial), or allow some trigonometric functions, or something like that.
If your setup were particularly easy, you'd have just linear equations, i.e. r = a*x + b*y + c. As you can see, even that has three parameters a,b,c so you can't uniquely find all three of them just given the two inputs you provided in your question. And even then the result would not be the r = x*y you were aiming for, since that's technically of degree 2.
If you want to point out that r = x*y is a particularly simple formula, and you would like to look for simple formulas, then one approach would be enumerating formulas in order of increasing complexity. But if you do this without parameters (since ugly parameters will make a simple formula like a*x + b*y + c appear complex), then it's hard to guilde this enumeration towards the one you want, so you'd really have to enumerate all possible formulas, which will become infeasible very quickly.
Why does the following code return a ValueError?
from scipy.optimize import fsolve
import numpy as np
def f(p,a=0):
x,y = p
return (np.dot(x,y)-a,np.outer(x,y)-np.ones((3,3)),x+y-np.array([1,2,3]))
x,y = fsolve(f,(np.ones(3),np.ones(3)),9)
ValueError: setting an array element with a sequence.
The basic problem here is that your function f does not satisfy the criteria required for fsolve to work. These criteria are described in the documentation - although arguably not very clearly.
The particular things that you need to be aware of are:
the input to the function that will be solved for must be an n-dimensional vector (referred to in the docs as ndarray), such that the value of x you want is the solution to f(x, *args) = 0.
the output of f must be the same shape as the x input to f.
Currently, your function takes a 2 member tuple of 1x3-arrays (in p) and a fixed scalar offset (in a). It returns a 3 member tuple of types (scalar,3x3 array, 1x3 array)
As you can see, neither condition 1 nor 2 is met.
It is hard to advise you on exactly how to fix this without being exactly sure of the equation you are trying to solve. It seems you are trying to solve some particular equation f(x,y,a) = 0 for x and y with x0 = (1,1,1) and y0 = (1,1,1) and a = 9 as a fixed value. You might be able to do this by passing in x and y concatenated (e.g. pass in p0 = (1,1,1,1,1,1) and in the function use x=p[:3] and y = p[3:] but then you must modify your function to output x and y concatenated into a 6-dimensional vector similarly. This depends on the exact function your are solving for and I can't work this out from the output of your existing f (i.e based on a dot product, outer product and sum based tuple).
Note that arguments that you don't pass in the vector (e.g. a in your case) will be treated as fixed values and won't be varied as part of the optimisation or returned as part of any solution.
Note for those who like the full story...
As the docs say:
fsolve is a wrapper around MINPACK’s hybrd and hybrj algorithms.
If we look at the MINPACK hybrd documentation, the conditions for the input and output vectors are more clearly stated. See the relevant bits below (I've cut some stuff out for clarity - indicated with ... - and added the comment to show that the input and output must be the same shape - indicated with <--)
1 Purpose.
The purpose of HYBRD is to find a zero of a system of N non-
linear functions in N variables by a modification of the Powell
hybrid method. The user must provide a subroutine which calcu-
lates the functions. The Jacobian is then calculated by a for-
ward-difference approximation.
2 Subroutine and type statements.
SUBROUTINE HYBRD(FCN,N,X, ...
...
FCN is the name of the user-supplied subroutine which calculates
the functions. FCN must be declared in an EXTERNAL statement
in the user calling program, and should be written as follows.
SUBROUTINE FCN(N,X,FVEC,IFLAG)
INTEGER N,IFLAG
DOUBLE PRECISION X(N),FVEC(N) <-- input X is an array length N, so is output FVEC
----------
CALCULATE THE FUNCTIONS AT X AND
RETURN THIS VECTOR IN FVEC.
----------
RETURN
END
N is a positive integer input variable set to the number of
functions and variables.
X is an array of length N. On input X must contain an initial
estimate of the solution vector. On output X contains the
final estimate of the solution vector.