根据多种约束算法

时间:2016-01-26 14:39:14

标签: algorithm linear-programming

我有以下向量(或C矩阵和V向量)和K1,K2,K3常数

Constraints      [c11 + c12 + c13 + ... + c1n] <= K1
                 [c21 + c22 + c23 + ... + c2n] <= K2
                 [c31 + c32 + c33 + ... + c3n] <= K3
-------------------------------------------------
Values           [ v1 +  v2 +  v3 + ... +  vn] -> Max

作为输入我得到C和V的值,作为输出我想提供 X向量,其中只包含0和1值,给我

          [c11 * x1 + c12 * x2 + c13 * x3 + ... + c1n * xn <= K1
          [c21 * x1 + c22 * x2 + c23 * x3 + ... + c2n * xn <= K2
          [c31 * x1 + c32 * x2 + c33 * x3 + ... + c3n * xn <= K3
          ------------------------------------------------------
          [ v1 * x1 +  v2 * x2 +  v3 * x3 + ... + vn *  xn] -> Max

作为一个简单的例子:

输入:

          K1 = 15
          K2 = 20
          K3 = 10

          c1 = [3, 6, 8]    | sum(c1 * X) <= 15 
          c2 = [8, 9, 3]    | sum(c2 * X) <= 20
          c3 = [7, 5, 2]    | sum(c3 * x) <= 10
           v = [2, 5, 3]    | sum( v * X) -> Max

输出提供X向量,使约束中的值最大化:

           X = [0, 1, 1]

我正在寻找一种优雅的算法(也可能是Java或C#实现),根据输入给出输出。我们可以假设约束的数量总是3,并且提供了C和V(以及K1,K2,K3)的所有值。

另一个简单的例子可能是:你有一个房间(3D),所以你的约束是宽度高度长度房间( K1 K2 K3 ),你有一个家具项目清单( n items )。所有i家具都有自己的 lenght c1i ),宽度 c2i )和身高< / em>( c3i )和值( vi )。您希望为房间打包最有价值的家具,适合房间尺寸。所以输出是一个n长的X变量,只包含0和1的值,如果xi = 1,第i个元素被选中在房间里,如果xi = 0,第i个元素将不被选中在房间里。

2 个答案:

答案 0 :(得分:1)

这是多维0-1背包问题,这是NP难的。

可以找到解决方法的概述here,这是一篇相对较新的研究论文here,以及python here中的遗传算法实现。

取自python实现(上面链接pyeasyga)就是这个例子:

from pyeasyga import pyeasyga

# setup data
data = [(821, 0.8, 118), (1144, 1, 322), (634, 0.7, 166), (701, 0.9, 195),
        (291, 0.9, 100), (1702, 0.8, 142), (1633, 0.7, 100), (1086, 0.6, 145),
        (124, 0.6, 100), (718, 0.9, 208), (976, 0.6, 100), (1438, 0.7, 312),
        (910, 1, 198), (148, 0.7, 171), (1636, 0.9, 117), (237, 0.6, 100),
        (771, 0.9, 329), (604, 0.6, 391), (1078, 0.6, 100), (640, 0.8, 120),
        (1510, 1, 188), (741, 0.6, 271), (1358, 0.9, 334), (1682, 0.7, 153),
        (993, 0.7, 130), (99, 0.7, 100), (1068, 0.8, 154), (1669, 1, 289)]

ga = pyeasyga.GeneticAlgorithm(data)        # initialise the GA with data
ga.population_size = 200                    # increase population size to 200 (default value is 50)

# define a fitness function
def fitness(individual, data):
    weight, volume, price = 0, 0, 0
    for (selected, item) in zip(individual, data):
        if selected:
            weight += item[0]
            volume += item[1]
            price += item[2]
    if weight > 12210 or volume > 12:
        price = 0
    return price

ga.fitness_function = fitness               # set the GA's fitness function
ga.run()                                    # run the GA
print ga.best_individual()                  # print the GA's best solution

data的最后一个维度是价格,另外两个维度是重量和体积。

您可以调整此示例,以便解决超过两个维度的问题。

我希望有所帮助。

编辑:遗传算法一般不能保证找到最优解。对于三个约束,它可能会找到好的解决方案,但不能保证最优性。

更新:数学优化解决方案

另一个选择是使用PuLP,一个用于数学优化问题的开源建模框架。该框架调用解算器,即专门设计用于解决优化问题的软件。简而言之,框架的工作是将数学问题描述与解决时需要的形式联系起来,求解器的工作就是实际解决问题。

您可以安装纸浆,例如pippip install pulp)。

以下是pulp中建模的上一个示例,通过修改this示例:

import pulp as plp

# Let's keep the same data
data = [(821, 0.8, 118), (1144, 1, 322), (634, 0.7, 166), (701, 0.9, 195),
        (291, 0.9, 100), (1702, 0.8, 142), (1633, 0.7, 100), (1086, 0.6, 145),
        (124, 0.6, 100), (718, 0.9, 208), (976, 0.6, 100), (1438, 0.7, 312),
        (910, 1, 198), (148, 0.7, 171), (1636, 0.9, 117), (237, 0.6, 100),
        (771, 0.9, 329), (604, 0.6, 391), (1078, 0.6, 100), (640, 0.8, 120),
        (1510, 1, 188), (741, 0.6, 271), (1358, 0.9, 334), (1682, 0.7, 153),
        (993, 0.7, 130), (99, 0.7, 100), (1068, 0.8, 154), (1669, 1, 289)]

w_cap, v_cap = 12210, 12

rng_items = xrange(len(data))

# Restructure the data in dictionaries
items = ['item_{}'.format(i) for i in rng_items]
weight = {items[i]: data[i][0] for i in rng_items}
volume = {items[i]: data[i][1] for i in rng_items}
price = {items[i]: data[i][2] for i in rng_items}

# Make the problem, declare it as a maximization problem
problem_name = "3D Knapsack"
prob = plp.LpProblem(problem_name, plp.LpMaximize)

# Define the variables
plp_vars = plp.LpVariable.dicts('', items, 0, 1, plp.LpInteger) 

# Objective function
prob += plp.lpSum([price[i]*plp_vars[i] for i in plp_vars])

# Constraints
prob += plp.lpSum([weight[i]*plp_vars[i] for i in plp_vars]) <= w_cap
prob += plp.lpSum([volume[i]*plp_vars[i] for i in plp_vars]) <= v_cap

# Solution
prob.solve()

# If you want to save the problem formulation in a file
# prob.writeLP(problem_name + 'lp')

# Each of the variables is printed with it's resolved optimum value
for v in prob.variables():
    print v.name, "=", v.varValue

# The optimised objective function value is printed to the screen    
print "Total gain = ", plp.value(prob.objective)

目标是3,540。

演示如何运行here

答案 1 :(得分:1)

它可以完全解决,例如使用Gurobi的C#绑定:

var env = new GRBEnv();
var model = new GRBModel(env);
var vars = model.AddVars(v.Length, GRB.BINARY);
model.Update();
GRBLinExpr obj = 0.0;
obj.AddTerms(v, vars, 0, v.Length);
model.SetObjective(obj, GRB.MAXIMIZE);
for (int i = 0; i < 3; i++) {
    GRBLinExpr expr = 0.0;
    for (int j = 0; j < C[i].Length; j++)
        expr.AddTerm(C[i][j], vars[j]);
    model.AddConstr(expr, GRB.LESS_EQUAL, K[i], "");
}
model.Update();
model.Optimize();

然后你可以在变量上调用Get(GRB.DoubleAttr.X)来获取它们的值。