Установка различных типов переменных и границ с помощью LpVariable.dicts - PullRequest
1 голос
/ 26 марта 2019

У меня проблема с линейным программированием, когда я пытаюсь найти оптимальный набор инвестиций для максимизации чистой приведенной стоимости с учетом бюджетных ограничений. Большинство из этих инвестиционных решений являются целочисленными (0/1), но некоторые из них могут быть частично профинансированы (непрерывно между 0 и 1). Я использую PuLP в Python и установил решения в качестве переменной словаря x, вместо того, чтобы иметь другую переменную, соответствующую решению для каждой переменной. Я не уверен, как назначить категории для x с помощью LpVariable.dicts, чтобы категория для целочисленных переменных была Integer, а для частично финансируемых переменных - Continuous.

У меня есть словарь целочисленных / непрерывных строк, сохраненных как переменная 'types', и переменная 'items', содержащая ключи словаря.

# Define dictionary keys
gc1=dict(zip(data['Investment ID'], data['Cost']))
items = list(gc1.keys())

# Define variable types
types=dict(zip(data['Investment ID'], np.where(data['Partial']==1, 'Continuous', 'Integer')))

# Define lp variable
x = LpVariable.dicts('x', items, lowBound=0, upBound=1, cat=types)

Оптимизация проходит успешно, однако некоторые решения, которые должны быть целочисленными (0/1), являются непрерывными.

Ответы [ 2 ]

1 голос
/ 28 марта 2019

Спасибо @kabdulla! Я также нашел другой способ сделать это, когда вы сначала устанавливаете одну категорию в LpVariable, а затем определяете категорию для каждого элемента переменной:

# Define dictionary keys
gc1=dict(zip(data['Investment ID'], data['Cost']))
items = list(gc1.keys())

# Define variable types
types=dict(zip(data['Investment ID'], np.where(data['Partial']==1, 'Continuous', 'Integer')))

# Define lp variable
x = LpVariable.dicts('x', items, lowBound=0, upBound=1, cat='Integer')
for i in items:
     x[i].cat=types[i]
0 голосов
/ 27 марта 2019

Насколько я знаю, метод LpVariable.dicts() может принимать только одну категорию - то есть его можно использовать для создания словаря переменных одного типа.

Вы можете либо создать 2 списка - список непрерывных и список целочисленных переменных, а затем использовать метод LpVariable.dicts() - либо, как показано ниже, просто создавать экземпляры переменных по одной за раз, что все еще очень легко с помощью понимания списка Python. , Как видите, все целочисленные переменные равны 1 или 0.

from pulp import *
import numpy as np

n_vars = 6
np.random.seed(0)

# Define some variable names and types
var_names = ['var_' + str(i) for i in range(n_vars)]
Partial = np.random.randint(2, size=n_vars)
types = np.where(Partial==1, 'Continuous', 'Integer')

# Create some returns
returns = np.random.rand(n_vars)

# Create some costs
costs = np.random.rand(n_vars)

# Allocate a budget
budget = 2.0

# Create list of contiuous variables
x_cont = [LpVariable(i, lowBound=0, upBound=1, cat=j) for i, j in zip(var_names, types)]

# Do an optimisation to check its worked:
prob = LpProblem("Mixed Problem", LpMaximize)
prob += lpSum([x_cont[i]*returns[i] for i in range(n_vars)])
prob += lpSum([x_cont[i]*costs[i] for i in range(n_vars)]) <= budget
prob.solve()

x_soln = np.array([x_cont[i].varValue for i in range(n_vars)])

print("costs: ", costs)
print("returns: ", returns)

print("types: ", types)
print("x_soln: ", x_soln)

Выход:

costs:  [0.38344152 0.79172504 0.52889492 0.56804456 0.92559664 0.07103606]
returns:  [0.54488318 0.4236548  0.64589411 0.43758721 0.891773   0.96366276]
types:  ['Integer' 'Continuous' 'Continuous' 'Integer' 'Continuous' 'Continuous']
x_soln:  [1.         0.11497788 1.         0.         1.         1.        ]
...