GEKKO在我的优化代码中为整数变量返回十进制值的原因是什么?

huangapple go评论55阅读模式
英文:

Why does GEKKO return a decimal value for an integer variable in my optimization code?

问题

GEKKO优化为整数变量返回小数值的原因可能是因为在解决优化问题时,某些约束条件或目标函数可能导致结果不是整数值。这通常是线性规划或混合整数规划问题中的情况。在您的情况下,您已经定义了一些约束和目标函数,这可能导致pcs的结果不是整数值。

您可以尝试以下方法来确保pcs是整数:

  1. 尝试调整约束条件或目标函数,以使其更符合整数解。
  2. 尝试不同的优化求解器,GEKKO支持多个求解器,可能会产生不同的结果。
  3. 考虑将pcs的界限扩展到更接近整数值的范围。

请注意,有时候,由于数值优化的特性,即使是整数规划问题也可能获得接近整数的结果。这些结果可能在实际应用中仍然是可接受的。

英文:

Why does GEKKO optimisation return a decimal value for an Integer variable?

Hello everyone,
With my GEKKO code I want to optimise a cutting pattern, with the maximum surface area of rectangles in the area of a circle.

All my variables are predefined and are integer:

  • diam: 1 diameter from the list
  • ep and larg: 1 thickness and 1 width linked together by dictionary
  • pcs: number of rectangles pieces, between 1 and 14 and also integer.

I could optimise my problem without Gekko, by testing all the possibilities with nested loops, but I want to add new variables afterwards, which would lead to too many possibilities for the loops.

I therefore use GEKKO with the principle of binary decision variables for almost all my variables.

from gekko import GEKKO 
m = GEKKO(remote=False)

#define diameter of circle
diam = [205,225,237,255,269,286,295,305]
xdiam = [m.Var(lb=0, ub=1, integer=True) for _ in diam]
m.Equation(sum(xdiam) == 1)

#define numbers of pieces
pcs = m.Var(lb=1, ub=14, integer=True, value=10)
#define thickness et width
dic = {
    12:[75,95,100],
    15:[95,100,150],
    10:[100,135,120]}
pair = []
for cle in dic:
    for val in dic[cle]:
        xpair = m.Var(lb=0,ub=1, integer=True)
        pair.append((cle,val, xpair))
m.Equation(sum(xl[2] for xl in pair) == 1)

#constraint : diagonal of all rectangles (hypotenuse) 
#  must not exceed the diameter
pyth = m.Intermediate((((sum((e*xe) for e,_,xe in pair))*pcs \
  +((pcs-1)*3.5))**2+(sum((l*xl) for _,l,xl in pair))**2)**0.5)
m.Equation(pyth <= sum((d*xd) for d, xd in zip(diam, xdiam)))

#Maximise area of rectangles/area of circle
rend = m.Intermediate(((sum((l*xl) for _,l,xl in pair))*(sum((e*xe) \
  for e,_,xe in pair))*pcs)/((((sum((d*xd) \
  for d, xd in zip(diam, xdiam)))*0.5)**2)*3.14))
m.Maximize(rend)

#Solver
m.options.SOLVER = 3
m.options.MAX_ITER = 1000 
m.solve()

#Display results
for ep,larg,bin in pair:
    if float(bin.value[0]) > 0.90:
        print("thi",ep)
        print("wid",larg)
for diam, xdiam in zip(diam,xdiam):
    if xdiam.VALUE[0] > 0.9:
        print("diam",diam)
print("pcs",pcs.VALUE[0])
print("yield",rend.VALUE[0])
print("pyth",pyth.VALUE[0])

And I don't know why the optimal solution proposed for the number of pieces is not an integer value?

In this example the pcs result is pretty close to an integer value, but by modifying the sections in the dictionary I can come up with values like : pcs = 5.820173.

 The solution was found.
The final value of the objective function is  -0.5289469114205082
---------------------------------------------------
Solver         :  IPOPT (v3.12)
Solution time  :  0.0211 sec
Objective      :  -0.5289469114205082
Successful solution
---------------------------------------------------
thi 15
wid 150
diam 205
pcs 7.9775445419
yield 0.52894691142
pyth 205.00005502

Thank you in advance

答案1

得分: 1

以下是您要翻译的内容:

"The correct solver needs to be selected. It is currently IPOPT with m.options.SOLVER = 3 as a Nonlinear Programming (NLP) solver that does not attempt to find an integer solution. However, the IPOPT solver is very good at finding an initial guess for the APOPT solver as a Mixed Integer Nonlinear Programming (MINLP) solver. By default, the minlp_integer_tol (integer tolerance) is 0.01. This means that 0.99 and 1.01 are both considered integer solutions. This tolerance can be adjusted to a more stringent requirement such as 1e-6. Try this sequence of solutions to find a more exact integer solution:

# Initialize with IPOPT (NLP Solver)
m.options.SOLVER = 3
m.solve()

# Find Integer solution with APOPT (MINLP Solver)
m.options.SOLVER = 1
m.solver_options = ['minlp_gap_tol 1.0e-4',
                    'minlp_integer_tol 1.0e-6',
                    'minlp_max_iter_with_int_sol 500']
m.solve()

The solution is:

 Successful solution
 
 ---------------------------------------------------
 Solver         :  APOPT (v1.0)
 Solution time  :   3.590000000258442E-002 sec
 Objective      :  -0.510288956224352     
 Successful solution
 ---------------------------------------------------
 
thi 15
wid 150
diam 237
pcs 10.0
yield 0.51028895622
pyth 235.46178034

Here is the complete script:

from gekko import GEKKO 
m = GEKKO(remote=True)

#define diameter of circle
diam = [205,225,237,255,269,286,295,305]
xdiam = [m.Var(lb=0, ub=1, integer=True) for _ in diam]
m.Equation(sum(xdiam) == 1)

#define numbers of pieces
pcs = m.Var(lb=1, ub=14, integer=True, value=10)
#define thickness et width
dic = {
    12:[75,95,100],
    15:[95,100,150],
    10:[100,135,120]}
pair = []
for cle in dic:
    for val in dic[cle]:
        xpair = m.Var(lb=0,ub=1, integer=True)
        pair.append((cle,val, xpair))
m.Equation(sum(xl[2] for xl in pair) == 1)

#constraint : diagonal of all rectangles (hypotenuse) 
#  must not exceed the diameter
pyth = m.Intermediate((((sum((e*xe) for e,_,xe in pair))*pcs \
  +((pcs-1)*3.5))**2+(sum((l*xl) for _,l,xl in pair))**2)**0.5)
m.Equation(pyth <= sum((d*xd) for d, xd in zip(diam, xdiam)))


#Maximise area of rectangles/area of circle
rend = m.Intermediate(((sum((l*xl) for _,l,xl in pair))*(sum((e*xe) \
  for e,_,xe in pair))*pcs)/((((sum((d*xd) \
  for d, xd in zip(diam, xdiam)))*0.5)**2)*3.14))
m.Maximize(rend)

m.options.MAX_ITER = 1000 

# Initialize with IPOPT (NLP Solver)
m.options.SOLVER = 3
m.solve()

# Find Integer solution with APOPT (MINLP Solver)
m.options.SOLVER = 1
m.solver_options = ['minlp_gap_tol 1.0e-4',
                    'minlp_integer_tol 1.0e-6',
                    'minlp_max_iter_with_int_sol 500']
m.solve()

#Display results
for ep,larg,bin in pair:
    if float(bin.value[0]) > 0.90:
        print("thi",ep)
        print("wid",larg)
for diam, xdiam in zip(diam,xdiam):
    if xdiam.VALUE[0] > 0.9:
        print("diam",diam)
print("pcs",pcs.VALUE[0])
print("yield",rend.VALUE[0])
print("pyth",pyth.VALUE[0])
英文:

The correct solver needs to be selected. It is currently IPOPT with m.options.SOLVER = 3 as a Nonlinear Programming (NLP) solver that does not attempt to find an integer solution. However, the IPOPT solver is very good at finding an initial guess for the APOPT solver as a Mixed Integer Nonlinear Programming (MINLP) solver. By default, the minlp_integer_tol (integer tolerance) is 0.01. This means that 0.99 and 1.01 are both considered integer solutions. This tolerance can be adjusted to a more stringent requirement such as 1e-6. Try this sequence of solutions to find a more exact integer solution:

# Initialize with IPOPT (NLP Solver)
m.options.SOLVER = 3
m.solve()

# Find Integer solution with APOPT (MINLP Solver)
m.options.SOLVER = 1
m.solver_options = ['minlp_gap_tol 1.0e-4',\
                    'minlp_integer_tol 1.0e-6',\
                    'minlp_max_iter_with_int_sol 500']
m.solve()

The solution is:

 Successful solution
---------------------------------------------------
Solver         :  APOPT (v1.0)
Solution time  :   3.590000000258442E-002 sec
Objective      :  -0.510288956224352     
Successful solution
---------------------------------------------------
thi 15
wid 150
diam 237
pcs 10.0
yield 0.51028895622
pyth 235.46178034

Here is the complete script:

from gekko import GEKKO 
m = GEKKO(remote=True)

#define diameter of circle
diam = [205,225,237,255,269,286,295,305]
xdiam = [m.Var(lb=0, ub=1, integer=True) for _ in diam]
m.Equation(sum(xdiam) == 1)

#define numbers of pieces
pcs = m.Var(lb=1, ub=14, integer=True, value=10)
#define thickness et width
dic = {
    12:[75,95,100],
    15:[95,100,150],
    10:[100,135,120]}
pair = []
for cle in dic:
    for val in dic[cle]:
        xpair = m.Var(lb=0,ub=1, integer=True)
        pair.append((cle,val, xpair))
m.Equation(sum(xl[2] for xl in pair) == 1)

#constraint : diagonal of all rectangles (hypotenuse) 
#  must not exceed the diameter
pyth = m.Intermediate((((sum((e*xe) for e,_,xe in pair))*pcs \
  +((pcs-1)*3.5))**2+(sum((l*xl) for _,l,xl in pair))**2)**0.5)
m.Equation(pyth <= sum((d*xd) for d, xd in zip(diam, xdiam)))


#Maximise area of rectangles/area of circle
rend = m.Intermediate(((sum((l*xl) for _,l,xl in pair))*(sum((e*xe) \
  for e,_,xe in pair))*pcs)/((((sum((d*xd) \
  for d, xd in zip(diam, xdiam)))*0.5)**2)*3.14))
m.Maximize(rend)

m.options.MAX_ITER = 1000 

# Initialize with IPOPT (NLP Solver)
m.options.SOLVER = 3
m.solve()

# Find Integer solution with APOPT (MINLP Solver)
m.options.SOLVER = 1
m.solver_options = ['minlp_gap_tol 1.0e-4',\
                    'minlp_integer_tol 1.0e-6',\
                    'minlp_max_iter_with_int_sol 500']
m.solve()

#Display results
for ep,larg,bin in pair:
    if float(bin.value[0]) > 0.90:
        print("thi",ep)
        print("wid",larg)
for diam, xdiam in zip(diam,xdiam):
    if xdiam.VALUE[0] > 0.9:
        print("diam",diam)
print("pcs",pcs.VALUE[0])
print("yield",rend.VALUE[0])
print("pyth",pyth.VALUE[0])

huangapple
  • 本文由 发表于 2023年5月31日 23:16:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/76375023.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定