将纸浆输出到numpy阵列

时间:2017-06-29 20:37:26

标签: python numpy pulp

我正在使用纸浆来解决具有许多变量的特定问题,混合了1-D,2-D和3-D变量。当获得解决方案时,我想将这些变量变为k维numpy数组。

变量:

u = pulp.LpVariable.dicts("u", (ns, ns), 0, 1, "Integer")
v = pulp.LpVariable.dicts("v", (ns, ns), 0, 1, "Integer")
w = pulp.LpVariable.dicts("w", (ns, ns, ps), 0, 1, "Integer")
x = pulp.LpVariable.dicts("x", (ns, ps), 0, 1, "Integer")
y = pulp.LpVariable.dicts("y", (ms, ps), 0, 1, "Integer")
z = pulp.LpVariable.dicts("z", (ns), parameters.hold_duration_min,
                          parameters.hold_duration_max, "Continuous")

varnames = {"u": u, "v": v, "w": w, "x": x, "y": y, "z": z}

输入(解决后):

problem.variables()

输出:

[u_0_1, u_0_2, u_0_3, u_0_4, u_0_5, u_0_6, u_1_2, u_1_3, u_1_4, u_1_5, u_1_6, u_2_3, u_2_4, u_2_5, u_2_6, u_3_4, u_3_5, u_3_6, u_4_5, u_4_6, u_5_6, v_0_1, v_0_2, v_0_3, v_0_4, v_0_5, v_0_6, v_1_2, v_1_3, v_1_4, v_1_5, v_1_6, v_2_3, v_2_4, v_2_5, v_2_6, v_3_4, v_3_5, v_3_6, v_4_5, v_4_6, v_5_6, w_0_1_0, w_0_1_1, w_0_1_2, w_0_1_3, w_0_1_4, w_0_1_5, w_0_1_6, w_0_2_0, w_0_2_1, w_0_2_2, w_0_2_3, w_0_2_4, w_0_2_5, w_0_2_6, w_0_3_0, w_0_3_1, w_0_3_2, w_0_3_3, w_0_3_4, w_0_3_5, w_0_3_6, w_0_4_0, w_0_4_1, w_0_4_2, w_0_4_3, w_0_4_4, w_0_4_5, w_0_4_6, w_0_5_0, w_0_5_1, w_0_5_2, w_0_5_3, w_0_5_4, w_0_5_5, w_0_5_6, w_0_6_0, w_0_6_1, w_0_6_2, w_0_6_3, w_0_6_4, w_0_6_5, w_0_6_6, w_1_0_0, w_1_0_1, w_1_0_2, w_1_0_3, w_1_0_4, w_1_0_5, w_1_0_6, w_1_2_0, w_1_2_1, w_1_2_2, w_1_2_3, w_1_2_4, w_1_2_5, w_1_2_6, w_1_3_0, w_1_3_1, w_1_3_2, w_1_3_3, w_1_3_4, w_1_3_5, w_1_3_6, w_1_4_0, w_1_4_1, w_1_4_2, w_1_4_3, w_1_4_4, w_1_4_5, w_1_4_6, w_1_5_0, w_1_5_1, w_1_5_2, w_1_5_3, w_1_5_4, w_1_5_5, w_1_5_6, w_1_6_0, w_1_6_1, w_1_6_2, w_1_6_3, w_1_6_4, w_1_6_5, w_1_6_6, w_2_0_0, w_2_0_1, w_2_0_2, w_2_0_3, w_2_0_4, w_2_0_5, w_2_0_6, w_2_1_0, w_2_1_1, w_2_1_2, w_2_1_3, w_2_1_4, w_2_1_5, w_2_1_6, w_2_3_0, w_2_3_1, w_2_3_2, w_2_3_3, w_2_3_4, w_2_3_5, w_2_3_6, w_2_4_0, w_2_4_1, w_2_4_2, w_2_4_3, w_2_4_4, w_2_4_5, w_2_4_6, w_2_5_0, w_2_5_1, w_2_5_2, w_2_5_3, w_2_5_4, w_2_5_5, w_2_5_6, w_2_6_0, w_2_6_1, w_2_6_2, w_2_6_3, w_2_6_4, w_2_6_5, w_2_6_6, w_3_0_0, w_3_0_1, w_3_0_2, w_3_0_3, w_3_0_4, w_3_0_5, w_3_0_6, w_3_1_0, w_3_1_1, w_3_1_2, w_3_1_3, w_3_1_4, w_3_1_5, w_3_1_6, w_3_2_0, w_3_2_1, w_3_2_2, w_3_2_3, w_3_2_4, w_3_2_5, w_3_2_6, w_3_4_0, w_3_4_1, w_3_4_2, w_3_4_3, w_3_4_4, w_3_4_5, w_3_4_6, w_3_5_0, w_3_5_1, w_3_5_2, w_3_5_3, w_3_5_4, w_3_5_5, w_3_5_6, w_3_6_0, w_3_6_1, w_3_6_2, w_3_6_3, w_3_6_4, w_3_6_5, w_3_6_6, w_4_0_0, w_4_0_1, w_4_0_2, w_4_0_3, w_4_0_4, w_4_0_5, w_4_0_6, w_4_1_0, w_4_1_1, w_4_1_2, w_4_1_3, w_4_1_4, w_4_1_5, w_4_1_6, w_4_2_0, w_4_2_1, w_4_2_2, w_4_2_3, w_4_2_4, w_4_2_5, w_4_2_6, w_4_3_0, w_4_3_1, w_4_3_2, w_4_3_3, w_4_3_4, w_4_3_5, w_4_3_6, w_4_5_0, w_4_5_1, w_4_5_2, w_4_5_3, w_4_5_4, w_4_5_5, w_4_5_6, w_4_6_0, w_4_6_1, w_4_6_2, w_4_6_3, w_4_6_4, w_4_6_5, w_4_6_6, w_5_0_0, w_5_0_1, w_5_0_2, w_5_0_3, w_5_0_4, w_5_0_5, w_5_0_6, w_5_1_0, w_5_1_1, w_5_1_2, w_5_1_3, w_5_1_4, w_5_1_5, w_5_1_6, w_5_2_0, w_5_2_1, w_5_2_2, w_5_2_3, w_5_2_4, w_5_2_5, w_5_2_6, w_5_3_0, w_5_3_1, w_5_3_2, w_5_3_3, w_5_3_4, w_5_3_5, w_5_3_6, w_5_4_0, w_5_4_1, w_5_4_2, w_5_4_3, w_5_4_4, w_5_4_5, w_5_4_6, w_5_6_0, w_5_6_1, w_5_6_2, w_5_6_3, w_5_6_4, w_5_6_5, w_5_6_6, w_6_0_0, w_6_0_1, w_6_0_2, w_6_0_3, w_6_0_4, w_6_0_5, w_6_0_6, w_6_1_0, w_6_1_1, w_6_1_2, w_6_1_3, w_6_1_4, w_6_1_5, w_6_1_6, w_6_2_0, w_6_2_1, w_6_2_2, w_6_2_3, w_6_2_4, w_6_2_5, w_6_2_6, w_6_3_0, w_6_3_1, w_6_3_2, w_6_3_3, w_6_3_4, w_6_3_5, w_6_3_6, w_6_4_0, w_6_4_1, w_6_4_2, w_6_4_3, w_6_4_4, w_6_4_5, w_6_4_6, w_6_5_0, w_6_5_1, w_6_5_2, w_6_5_3, w_6_5_4, w_6_5_5, w_6_5_6, x_0_0, x_0_1, x_0_2, x_0_3, x_0_4, x_0_5, x_0_6, x_1_0, x_1_1, x_1_2, x_1_3, x_1_4, x_1_5, x_1_6, x_2_0, x_2_1, x_2_2, x_2_3, x_2_4, x_2_5, x_2_6, x_3_0, x_3_1, x_3_2, x_3_3, x_3_4, x_3_5, x_3_6, x_4_0, x_4_1, x_4_2, x_4_3, x_4_4, x_4_5, x_4_6, x_5_0, x_5_1, x_5_2, x_5_3, x_5_4, x_5_5, x_5_6, x_6_0, x_6_1, x_6_2, x_6_3, x_6_4, x_6_5, x_6_6, y_0_0, y_0_1, y_0_2, y_0_3, y_0_4, y_0_5, y_0_6, y_1_0, y_1_1, y_1_2, y_1_3, y_1_4, y_1_5, y_1_6, y_2_0, y_2_1, y_2_2, y_2_3, y_2_4, y_2_5, y_2_6, y_3_0, y_3_1, y_3_2, y_3_3, y_3_4, y_3_5, y_3_6, y_4_0, y_4_1, y_4_2, y_4_3, y_4_4, y_4_5, y_4_6, y_5_0, y_5_1, y_5_2, y_5_3, y_5_4, y_5_5, y_5_6, y_6_0, y_6_1, y_6_2, y_6_3, y_6_4, y_6_5, y_6_6, y_7_0, y_7_1, y_7_2, y_7_3, y_7_4, y_7_5, y_7_6, y_8_0, y_8_1, y_8_2, y_8_3, y_8_4, y_8_5, y_8_6, z_0, z_1, z_2, z_3, z_4, z_5, z_6]

我想要生成的是用于保存结果的numpy数组的字典,例如results,例如:

results["x"][1][4] == pulp.value(x[1][4])
type(results["x"]) == numpy.ndarray
results["z"][2] == pulp.value(z[2])
results(["w"][6][0][2]) == pulp.value(w[6][0][2])

我尝试了一些使用例如大熊猫,但不能让它适用于我的1-D,2-D和3-D阵列组合:

results = {}
vfunc = numpy.vectorize(lambda i: pulp.value(i))
for k, v in varnames.items():
    try:
        results[k] = vfunc(pandas.DataFrame(v).values)
    except:
        pass

......以上适用于2D变量,但不适用于1-D或3-D。

编辑:我最近在另一个项目上回到了这个问题,并通过为多维变量定义一个新类来更彻底地解决了这个问题:

import pulp
import numpy


class MultiDimensionalLpVariable:
    def __init__(self, name, dimensions, low_bound, up_bound, cat):
        self.name = name
        try:
            self.dimensions = (*dimensions,)
        except:
            self.dimensions = (dimensions,)
        self.low_bound = low_bound
        self.up_bound = up_bound
        assert cat in pulp.LpCategories, 'cat must be one of ("{}").'.format(
            '", "'.join(pulp.LpCategories)
        )
        self.cat = cat
        self.variables = self._build_variables_array()
        self.values = None

    def __getitem__(self, index):
        return self.variables[index]

    def _build_variables_array(self):
        f = numpy.vectorize(self._define_variable)
        return numpy.fromfunction(f, self.dimensions, dtype="int")

    def _define_variable(self, *index):
        name = "_".join(map(str, (self.name, *index)))
        return pulp.LpVariable(name, self.low_bound, self.up_bound, self.cat)

    def evaluate(self):
        f = numpy.vectorize(lambda i: pulp.value(i))
        self.values = f(self.variables)

我现在可以按如下方式定义一个新变量:

x = MultiDimensionalLpVariable("x",(10,20), 0, 1, "Binary")

可以通过例如

来访问个别变量
>>> x[1,2]
x_1_2

或:

>>> x[1][2]
x_1_2

这允许以明确的语法实现约束,例如,等式:

enter image description here

可以写成:

for n in range(N):
        problem += sum([x[n][p] for p in range(P)]) == 1

这种方法可以推广到任意数量的维度。

问题解决后,可以获得变量值

>>> x.evaluate()
>>> x.values
array([[1., 0., 0., 0., 0.],
       [0., 0., 1., 0., 0.],
       [1., 0., 0., 0., 0.],
       [0., 0., 1., 0., 0.],
       [0., 0., 0., 1., 0.]])

可以通过例如

来访问单个变量值
>>> x.values[1,2]
1.0

或:

>>> x.values[1][2]
1.0

3 个答案:

答案 0 :(得分:1)

编辑:忽略此解决方案 - 找到一个更简洁的方法,请参阅原始问题陈述。

我最终解决了这个问题。

使用多维变量的类结构可能对其他人有用。

关键在于定义函数来在numpy数组和一系列dicts之类的字典之间进行转换。

然后,这允许在解决方案上以矢量化的方式在阵列上执行评估,给出一个可用于进一步处理的numpy解决方案值。

它还允许使用相对干净的语法来定义多维LP约束。

import numpy as np
import pulp

class Variable_Matrix:

    def __init__(self, name, dimensions, low_bound, up_bound, cat):
        self.name = name
        self.dimensions = dimensions
        self.low_bound = low_bound
        self.up_bound = up_bound
        self.cat = cat
        self.variable_objects = unflatten_variable(
                pulp.LpVariable.dicts(self.name,
                                      tuple([range(i) for i in dimensions]),
                                      self.low_bound, self.up_bound, self.cat),
                                      self.dimensions)
        self.values = np.empty(self.dimensions)

    def __getitem__(self, index):
        return self.variable_objects(index)

    def evaluate(self):
        vectorized_evaluation = np.vectorize(lambda i: pulp.value(i))
        self.values = vectorized_evaluation(self.variable_objects)

# Generator for accessing components of a variable, returning the component and
# its position
def variable_iterator_loc(variable, dimensions):
    index = [0]* len(dimensions)
    depth = 0
    yield from _variable_iterator_loc(variable, dimensions, index, depth)


# Recursive function called by variable_iter_loc
def _variable_iterator_loc(variable, dimensions, index, depth):
    depth += 1
    if len(dimensions) == 1:
        for i in range(dimensions[0]):
            index[depth - 1] = i
            yield variable[i], tuple(index)
    else:
        for i in range(dimensions[0]):
            index[depth - 1] = i
            yield from _variable_iterator_loc(variable[i], dimensions[1:],
                                              index, depth)


# create a k-dimensional numpy array of variable objects, given the variable
# as a (dict of dict of ... of dicts) of depth k.
def unflatten_variable(variable, dimensions):
    unflattened = np.empty(dimensions, object)
    variter = variable_iterator_loc(variable, dimensions)
    for i in range(np.prod(dimensions)):
        varobject, position = next(variter)
        unflattened[position] = varobject
    return unflattened

这允许使用干净的语法来定义多维变量,例如:

x = Variable_Matrix("x", (N, N, P), 0, 1, "Integer")
y = Variable_Matrix("y", (N, P), 0, 1, "Integer")
z = Variable_Matrix("z", (N,), c_min, c_max, "Continuous")

这反过来允许在定义多维约束时使用干净的语法,例如:

problem = pulp.LpProblem("My Problem", pulp.LpMinimize)

for n in range(N):
    problem += sum([y[n][p] for p in range(P)]) == 1

结果可以按如下方式生成(一旦LP解决):

y.evaluate()

可以访问,例如如下:

y.values[2,3]

上述内容需要大量额外的功能和复杂性,但最终目标是使用非常干净的语法来构建LP方程式,并且可以很好地检索结果和抽象到具有多个维度的变量。

答案 1 :(得分:0)

最初,您的结果(在Pulp中)存储在字典中,但未按数组排序。因此,您需要在ndarray中的正确位置提取它们。另外在我的情况下,变量中有一些我不关心的松弛变量,所以我需要首先提取完整的含义。

#storing Optimisation result (alpha & beta) in a new dictionary
varDic = {}
for v in prob.variables():
    if v.name[:5] == 'alpha' or v.name == 'b':
        varDic[v.name] = v.varValue

#passing solution (alpha, beta) to proper ndarray
b = varDic['b']
del varDic['b'] #remove beta from dictionary so only alpha is left

x = np.zeros(N)
#storing the value of alpha_i in x(i)
for key in varDic:
    x[int(key[6:])] = varDic[key]

答案 2 :(得分:0)

现在老问题,但为了我自己的利益,有更好的(或至少是另一种)方式来做到这一点。它实际上是使用您为变量字典分配的对象:

u = pulp.LpVariable.dicts("u", (ns, ns), 0, 1, "Integer") v = pulp.LpVariable.dicts("v", (ns, ns), 0, 1, "Integer") w = pulp.LpVariable.dicts("w", (ns, ns, ps), 0, 1, "Integer") x = pulp.LpVariable.dicts("x", (ns, ps), 0, 1, "Integer") y = pulp.LpVariable.dicts("y", (ms, ps), 0, 1, "Integer") z = pulp.LpVariable.dicts("z", (ns), parameters.hold_duration_min, parameters.hold_duration_max, "Continuous")

解决问题后,您可以通过以下方式获取解决方案的数组:

u_soln = np.array([[u[i][j].varValue for i in ns] for j in ns])