【问题标题】:Way to solve constraint satisfaction faster than brute force?比蛮力更快地解决约束满足的方法?
【发布时间】:2016-07-13 14:20:47
【问题描述】:

我有一个 CSV,它为每行的三个不同 x 值提供一个 y 值。当读入 pandas DataFrame 时,它​​看起来像这样:

     5     10    20
0 -13.6 -10.7 -10.3
1 -14.1 -11.2 -10.8
2 -12.3  -9.4  -9.0

也就是说,对于第 0 行,第 5 行的值为 -13.6,第 10 行的值为 -10.7,第 20 行的值为 -10.3。这些值是以下形式的算法的结果:

def calc(x, r, b, c, d):
    if x < 10:
        y = (x * r + b) / x
    elif x >= 10 and x < 20:
        y = ((x * r) + (b - c)) / x
    else:
        y = ((x * r) + (b - d)) / x
    return y

我想找到每一行的 r、b、c 和 d 的值。我知道关于每个价值观的某些事情。例如,对于每一行:r 在 np.arange(-.05, -.11, -.01) 中,b 在 np.arange(0, -20.05, -.05) 中,c 和 d 在np.arange(0, 85, 5)。我也知道 d 是

目前,我正在用蛮力解决这个问题。对于每一行,我遍历 r、b、c 和 d 的每个组合,并测试三个 x 值的值是否等于 DataFrame 中的已知值。这行得通,为每一行提供了一些基本相同的组合,除了舍入差异。

问题在于,当我需要针对 2,000 多行运行它时,这种方法需要很长时间。我的问题是:有没有比迭代和测试每个组合更快的方法?我的理解是这是一个约束满足问题,但在那之后,我不知道要缩小什么范围;有这么多类型的约束满足问题(似乎)我仍然迷路(我什至不确定这是一个这样的问题!)。任何帮助我指出正确方向的帮助将不胜感激。

【问题讨论】:

    标签: python constraint-programming


    【解决方案1】:

    我希望我正确理解了这个任务。

    如果你知道参数的分辨率/离散化,它看起来像是一个离散优化问题(通常:hard),可以通过 CP 方法解决。

    但如果您允许这些值是连续的(并重新制定公式),则为:

    • (1) 线性规划:如果检查可行值(需要有一个有效的解决方案)
    • (2) 线性规划:如果优化参数以最小化绝对差之和 (=errors)
    • (3) 二次规划:如果优化参数以最小化平方差之和(=误差)/相当于最小化欧几里得范数

    三个版本都可以高效解决!

    这里是 (3) 的非通用(可以很容易地推广)实现,使用cvxpy 来制定问题,ecos 来解决 QP。这两个工具都是开源的。

    代码

    import numpy as np
    import time
    from cvxpy import *
    from random import uniform
    
    """ GENERATE TEST DATA """
    def sample_params():
        while True:
            r = uniform(-0.11, -0.05)
            b = uniform(-20.05, 0)
            c = uniform(0, 85)
            d = uniform(0, 85)
            if d <= c:
                return r, b, c, d
    
    def calc(x, r, b, c, d):
        if x < 10:
            y = (x * r + b) / x
        elif x >= 10 and x < 20:
            y = ((x * r) + (b - c)) / x
        else:
            y = ((x * r) + (b - d)) / x
        return y
    
    N = 2000
    sampled_params = [sample_params() for i in range(N)]
    data_5 = np.array([calc(5, *sampled_params[i]) for i in range(N)])
    data_10 = np.array([calc(10, *sampled_params[i]) for i in range(N)])
    data_20 = np.array([calc(20, *sampled_params[i]) for i in range(N)])
    data = np.empty((N, 3))
    for i in range(N):
        data[i, :] = [data_5[i], data_10[i], data_20[i]]
    
    """ SOLVER """
    def solve(row):
        """ vars """
        R = Variable(1)
        B = Variable(1)
        C = Variable(1)
        D = Variable(1)
        E = Variable(3)
    
        """ constraints """
        constraints = []
        # bounds
        constraints.append(R >= -.11)
        constraints.append(R <= -.05)
        constraints.append(B >= -20.05)
        constraints.append(B <= 0.0)
        constraints.append(C >= 0.0)
        constraints.append(C <= 85.0)
        constraints.append(D >= 0.0)
        constraints.append(D <= 85.0)
        constraints.append(D <= C)
        # formula of model
        constraints.append((1.0 / 5.0) * B + R == row[0] + E[0])  # alternate function form: b/x+r
        constraints.append((1.0 / 10.0)  * B - (1.0 / 10.0) * C == row[1] + E[1])  # alternate function form: b/x-c/x+r
        constraints.append((1.0 / 20.0)  * B - (1.0 / 20.0) * D == row[2] + E[2])  # alternate function form: b/x-d/x+r
    
        """ Objective """
        objective = Minimize(norm(E, 2))
    
        """ Solve """
        problem = Problem(objective, constraints)
        problem.solve(solver=ECOS, verbose=False)
        return R.value, B.value, C.value, D.value, E.value
    
    start = time.time()
    for i in range(N):
        r, b, c, d, e = solve(data[i])
    end = time.time()
    
    print('seconds taken: ', end-start)
    print('seconds per row: ', (end-start) / N)
    

    输出

    ('seconds taken: ', 20.620506048202515)
    ('seconds per row: ', 0.010310253024101258)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-13
      • 2023-03-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多