Haz todo lo posible por entender el código bien antes de adaptarlo a tu trabajo y si ttienes algo que aportar puedes compartirlo con nosotros.
Solución:
solución de pulpa
Después de algunas investigaciones, no creo que su función objetivo sea lineal. Recreé el problema en la biblioteca pulp de Python, pero a pulp no le gusta que estemos dividiendo por un flotador y ‘LpAffineExpression’. Esta respuesta sugiere que la programación lineal “no comprende las divisiones”, pero ese comentario está en el contexto de agregar restricciones, no la función objetivo. Ese comentario me señaló “Programación fraccional lineal de enteros mixtos (MILFP)” y en Wikipedia.
Así es como podría hacerlo en pulpa si realmente funcionara (tal vez alguien pueda averiguar por qué):
import pulp
data = [(481.79, 5), (412.04, 4), (365.54, 3)] #, (375.88, 3), (379.75, 3), (632.92, 5), (127.89, 1), (835.71, 6), (200.21, 1)]
x = pulp.LpVariable.dicts('x', range(len(data)), lowBound=0, upBound=7, cat=pulp.LpInteger)
numerator = dict((i,tup[0]) for i,tup in enumerate(data))
denom_int = dict((i,tup[1]) for i,tup in enumerate(data))
problem = pulp.LpProblem('Mixed Integer Linear Programming', sense=pulp.LpMinimize)
# objective function (doesn't work)
# TypeError: unsupported operand type(s) for /: 'float' and 'LpAffineExpression'
problem += sum([numerator[i] / (denom_int[i] + x[i]) for i in range(len(data))])
problem.solve()
for v in problem.variables():
print(v.name, "=", v.varValue)
solución bruta con scipy.optimize
Puedes usar brute
y rangos de slice
s para cada x
en su función. Si tienes 3 x
s en su función, también tendrá 3 slice
s en su tupla de rangos. El key a todo esto es para agregar el paso tamaño de 1
al slice(start, stop,
step
)
entonces slice(#, #, 1)
.
from scipy.optimize import brute
import itertools
def f(x):
return (481.79/(5+x[0]))+(412.04/(4+x[1]))+(365.54/(3+x[2]))
ranges = (slice(0, 9, 1),) * 3
result = brute(f, ranges, disp=True, finish=None)
print(result)
solución itertools
O puede usar itertools para generar todas las combinaciones:
combinations = list(itertools.product(*[[0,1,2,3,4,5,6,7,8]]*3))
values = []
for combination in combinations:
values.append((combination, f(combination)))
best = [c for c,v in values if v == min([v for c,v in values])]
print(best)
Nota: esta es una versión reducida de su función original para fines de ejemplo.
Una cosa que podría ayudar a su problema podría tener una restricción como:
max([x-int(x)])=0
Esto no va a resolver completamente su problema, el algoritmo aún intentará hacer trampa y obtendrá valores con algún nivel de error. ~±5e-10
que todavía tratará de optimizar solo por el error en el algoritmo de scipy, pero es mejor que nada.
cons = ('type':'eq', 'fun': con,
'type':'eq','fun': lambda x : max([x[i]-int(x[i]) for i in range(len(x))]))
Después de haber probado este proceso en algunas optimizaciones, conozco la solución, este proceso es más sensible a los valores iniciales que la búsqueda sin restricciones, obtiene respuestas bastante precisas, sin embargo, es posible que la solución no encuentre el true valor, básicamente está requiriendo el gran salto del proceso de optimización (lo que usa para asegurarse de que no está optimizando a un mínimo local) para buscar en el espacio muestral, ya que los incrementos más pequeños generalmente no son lo suficientemente fuertes como para pasar al siguiente número.
Aquí hay una forma de resolver el problema de programación no lineal de enteros mixtos con Python Gekko (un paquete que mantengo):
from gekko import GEKKO
m = GEKKO(remote=False)
x = m.Array(m.Var,9,lb=0,ub=7,integer=True)
def f(x):
return (481.79/(5+x[0]))+(412.04/(4+x[1]))
+(365.54/(3+x[2]))+(375.88/(3+x[3]))
+(379.75/(3+x[4]))+(632.92/(5+x[5]))
+(127.89/(1+x[6]))+(835.71/(6+x[7]))
+(200.21/(1+x[8]))
m.Minimize(f(x))
m.Equation(sum(x)==7)
m.options.SOLVER=1
m.solve()
print(x)
Esto da la solución:
---------------------------------------------------
Solver : APOPT (v1.0)
Solution time : 0.0529 sec
Objective : 859.5269999999999
Successful solution
---------------------------------------------------
[[0.0] [0.0] [1.0] [1.0] [1.0] [0.0] [1.0] [0.0] [3.0]]
Si posees algún recelo o capacidad de progresar nuestro sección eres capaz de escribir un paráfrasis y con deseo lo ojearemos.