简体   繁体   中英

Python linear programming - how to constrain a variable to be an integer

I would like to maximize the probability of winning a raffle by buying a certain number of tickets. For this, I wrote the following code

import numpy as np
import math as mt
from scipy.optimize import minimize
from pulp import *

def objective(tickets, winners = 500, losers = 2500, cost_of_ticket = 40, winning_amt = 1000):

    Pwin = 1 - mt.factorial(losers)//mt.factorial(losers - tickets)*mt.factorial(winners+losers-tickets)/mt.factorial(winners+losers)
    Ewin = Pwin*(winning_amt - cost_of_ticket*tickets)

    return Ewin


# declare your variables
tickets = LpVariable("tickets", range(0, 10))   # 0<= tickets <= 10

prob = LpProblem("problem", LpMaximize)

#define the objective
prob += objective(tickets)

# solve the problem
status = prob.solve(GLPK(msg=0))
LpStatus[status]

# print the results
value(tickets)

The issue seems to be that the number of tickets that get passed into the objective function is not an integer (and the factorial function then fails). Can anyone suggest how I should ensure that the ticket is restricted to positive integer values?

The answer, for checking, should be 8. I can do this by manually calling the objective function and checking.

Your objective is really

 ExpWin(t) = choose(N,t)*(A-C*t)

where t is an integer variable and N,A,C are constants. This is a nonlinear function so a linear MIP solver will not be able to handle this.

For this problem it is silly, but in general we can linearize this. Introduce binary variables x(i) with:

x(i) = 1 if tickets=i
       0 otherwise

This can be enforced by

sum(i,x(i)) = 1
sum(i,i*x(i)) = tickets

This only makes sense if the range of variable tickets is small (in your case 10). Now we can precalculate a constant array w(i) which is the expected win if the number of tickets is i. Now the objective can look like:

max sum(i, w(i)*x(i))

which is now linear.

Anyway it is always a good idea to step away from code and write down the problem in math. This can help you think about the problem in a different way.

You can restrict a variable to integers when you define it:

tickets = LpVariable("tickets", range(0, 10), cat='Integer') # 0<= tickets <= 10

As per sascha's comment, this is explained here

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM