user1936752
user1936752

Reputation: 858

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.

Upvotes: 0

Views: 2988

Answers (2)

Flexecute
Flexecute

Reputation: 106

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

Upvotes: 0

Erwin Kalvelagen
Erwin Kalvelagen

Reputation: 16782

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.

Upvotes: 1

Related Questions