【问题标题】:Efficient Dynamic programming using Python使用 Python 进行高效的动态编程
【发布时间】:2018-06-21 17:25:31
【问题描述】:

我正在从事一项动态编程任务,即沿着有向图查找最小成本路径(所有可能的路径具有相同数量的加权节点)。

解决问题的方法是递归函数和动态规划。

由于在代码过程中会遇到许多不相关的问题,因此线程的概念可能会有所帮助。

问题是,在 python 中,'threading' 没有多大帮助。 在 python 中处理此类任务的有效方法是什么?

代码如下:

    def rec_fun(pos, path_size, weights, directions):
        cost = weights[d][i, j]
        if path_size == 0:
            key = str(i) + ',' + str(j) + ',' + str(d)
            dict.update({key: pix_cost})
            return cost
        else:
            key = str(i) + ',' + str(j) + ',' + str(d)
            if key in dict:
                return dict[key]
            else:

                val = cost + min(rec_fun(pos + direction[0], path_size - 1, weights, direction),
                                 rec_fun(pos + direction[1], path_size - 1, weights, direction),
                                 rec_fun(pos + direction[2], path_size - 1, weights, direction))
                dict.update({key: val})
                return val

【问题讨论】:

  • 所以...不要使用线程?我看不出是什么促使您首先要引入线程。动态编程不需要甚至不建议使用线程。
  • 动态编程的重点不就是将子问题的解决方案存储在内存中以防止重做工作吗?线程化方法会使这变得困难。
  • @user2357112:这只是进一步提高效率的想法。
  • @Patrick Haugh:是的,这是主要思想。我们的问题是由许多不相关的子问题创建的,每个子问题都是使用动态规划解决的。这就是我发表线程评论的原因。
  • 您的方法可以使用两个 for 循环和无递归来重写。然后你就会明白为什么线程不是进一步优化的方法。您可能正在考虑在不同线程中运行三个方向的成本计算,但这违背了动态规划的目的。

标签: python dynamic-programming


【解决方案1】:

首先,动态编程只是解决某种类型问题的简单范例。总体而言,您实际上无法做一些具体的事情来优化动态编程,这反过来意味着应用了一般的 Python 优化。

所以从你发布的代码中我看到的最引人注目的事情是递归的使用,这在 python 中效率相对较低,所以从移动到for(理想)或while循环开始。

以下是使您的代码在 python 中运行得更快的可能方法的非详尽列表(通过越来越多的努力):

  1. 尝试Numba 显着加快您的功能。在某些情况下,只需很少的工作(通常@jit 装饰器就足够了)将您的代码优化到几乎 cython 级别。

  2. 尽可能使用Numpy 对代码进行矢量化处理。

  3. 使用进程multiprocessing.Process 而不是线程,正如您可能已经想到的那样,由于全局解释器锁定,python 线程的工作方式与其他编程语言不同。我认为这里需要注意的是,在进程之间共享内存并不是一个真正的好习惯,你应该尽可能避免这种做法。

  4. 使用 Python 的 C 扩展 Cython 编写代码的所有性能关键部分。

【讨论】:

    【解决方案2】:

    使用 Python 3,您可以使用 functools 中的 lru_cache 缓存递归调用的结果,从而轻松实现动态编程。

    你可以这样包装你的函数:

    @functools.lru_cache(max_size=None)
    def rec_fun(pos, path_size, weights, directions):
        # your code...
    

    注意:由于这会缓存所有调用,因此与使用您自己的数组或列表实现 DP 相比,它可以存储比您需要的更多的结果。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-06-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-20
      • 1970-01-01
      • 2015-12-27
      相关资源
      最近更新 更多