2

Apologies in advance, I just started to learn Gekko to see if I can use it for a project. I'm trying to optimize the win rate while playing a game with very finite game-states (50 ^ 2) and options per turn (0-10 inclusive).

From what I understand, I can use the m.solve() Gekko function to minimize the win rate of the opponent which I've set up here:

PLAYER_MAX_SCORE = 50 #Score player needs to win
OPPONENT_MAX_SCORE = 50 #Score opponent needs to win

#The opponent's current strategy: always roll 4 dice per turn
OPPONENT_MOVE = 4

m = GEKKO()
m.options.SOLVER = 1

"""
player_moves is a 2-d array where:
 - the row represents player's current score
 - the column represents opponent's current score
 - the element represents the optimal move for the above game state
Thus the player's move for a game is player_moves[pScore, oScore].value.value
"""
player_moves = m.Array(m.Var, (PLAYER_MAX_SCORE, OPPONENT_MAX_SCORE), value=3, lb=0, ub=10, integer=True)

m.Obj(objective(player_moves, OPPONENT_MOVE, PLAYER_MAX_SCORE, OPPONENT_MAX_SCORE, 100))

m.solve(disp=False)

For reference, objective is a function that returns the win rate of the opponent based on how the current player acts (represented in player_moves).

The only issue is that m.solve() only calls the objective function once and then immediately returns the "solved" values in the player_moves array (which turn out to just be the initial values when player_moves was defined). I want m.solve() to call the objective function multiple times to determine if the new opponent's win rate is decreasing or increasing.

Is this possible with Gekko? Or is there a different library I should use for this type of problem?

Everbolt
  • 23
  • 5

1 Answers1

0

Gekko creates a symbolic representation of the optimization problem that is compiled into byte-code. For this reason, the objective function must be expressed with Gekko variables and equations. For black-box models that do not use Gekko variables, an alternative is to use scipy.optimize.minimize(). There is a comparison of Gekko and Scipy.

Scipy

import numpy as np
from scipy.optimize import minimize

def objective(x):
    return x[0]*x[3]*(x[0]+x[1]+x[2])+x[2]

def constraint1(x):
    return x[0]*x[1]*x[2]*x[3]-25.0

def constraint2(x):
    sum_eq = 40.0
    for i in range(4):
        sum_eq = sum_eq - x[i]**2
    return sum_eq

# initial guesses
n = 4
x0 = np.zeros(n)
x0[0] = 1.0
x0[1] = 5.0
x0[2] = 5.0
x0[3] = 1.0

# show initial objective
print('Initial Objective: ' + str(objective(x0)))

# optimize
b = (1.0,5.0)
bnds = (b, b, b, b)
con1 = {'type': 'ineq', 'fun': constraint1} 
con2 = {'type': 'eq', 'fun': constraint2}
cons = ([con1,con2])
solution = minimize(objective,x0,method='SLSQP',\
                    bounds=bnds,constraints=cons)
x = solution.x

# show final objective
print('Final Objective: ' + str(objective(x)))

# print solution
print('Solution')
print('x1 = ' + str(x[0]))
print('x2 = ' + str(x[1]))
print('x3 = ' + str(x[2]))
print('x4 = ' + str(x[3]))

Gekko

from gekko import GEKKO    
import numpy as np

#Initialize Model
m = GEKKO()

#initialize variables
x1,x2,x3,x4 = [m.Var(lb=1,ub=5) for i in range(4)]

#initial values
x1.value = 1
x2.value = 5
x3.value = 5
x4.value = 1

#Equations
m.Equation(x1*x2*x3*x4>=25)
m.Equation(x1**2+x2**2+x3**2+x4**2==40)

#Objective
m.Minimize(x1*x4*(x1+x2+x3)+x3)

#Solve simulation
m.solve()

#Results
print('')
print('Results')
print('x1: ' + str(x1.value))
print('x2: ' + str(x2.value))
print('x3: ' + str(x3.value))
print('x4: ' + str(x4.value))
John Hedengren
  • 12,068
  • 1
  • 21
  • 25
  • 1
    I used Gekko because it has a feature for "integer-only" parameters whereas scipy seems to primarily only allow floats for parameters. Is there any way to get around this? – Everbolt Sep 14 '21 at 20:11
  • Most solvers will also need the same type of information or require a particular type of variable. Here are some additional options that may help: https://stackoverflow.com/questions/26305704/python-mixed-integer-linear-programming – John Hedengren Sep 16 '21 at 00:12