Python是一个带有集合字典的优化函数

Python是一个带有集合字典的优化函数,python,optimization,numba,Python,Optimization,Numba,我正在尝试执行100K+蒙特卡罗模拟,并多次调用函数simulate来执行此操作。我正在研究使用Nubma来实现这一点,可能需要一些帮助,特别是我需要做集合的交集和并集 这是我试图优化的代码的一个最低限度的工作示例。似乎Numba不支持集合字典,如果我使用numpy数组字典,那么我就无法访问np.intersect1d和np.union1d将其转换为Numba需要任何帮助,或者它不适合Numba优化 import random import numpy as np from numba imp

我正在尝试执行100K+蒙特卡罗模拟,并多次调用函数
simulate
来执行此操作。我正在研究使用Nubma来实现这一点,可能需要一些帮助,特别是我需要做集合的交集和并集

这是我试图优化的代码的一个最低限度的工作示例。似乎Numba不支持集合字典,如果我使用numpy数组字典,那么我就无法访问
np.intersect1d
np.union1d
将其转换为Numba需要任何帮助,或者它不适合Numba优化

import random
import numpy as np

from numba import types, jit
from numba.typed import Dict, List

n_positions = 100
position_coverage = 10
min_dist = 5

n_ids = 5

near_dict = {x: set(range(x, x + position_coverage)) 
                if x < n_positions - position_coverage else 
                set(range(x, n_positions)) for x in range(n_positions)}
# near_dict = {0: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 1: {1, 2, 3, 4, 5, 6, 7, ...
close_dict = {x: set(range(x, x + min_dist)) 
                if x < n_positions - position_coverage + min_dist else 
                set(range(x, n_positions)) for x in range(n_positions)}
# close_dict = {0: {0, 1, 2, 3, 4}, 1: {1, 2, 3, 4, 5}, 2: {2, 3, 4, 5, ...

near_dict = {k: near_dict[k] for k in random.sample(near_dict.keys(), n_ids)}

@jit(nopython=True)
def simulate(near_dict, close_dict):
    out_dict = {}
    to_pos = None
    to_close = set()
    for id, near in sorted(near_dict.items(), key=lambda x: random.random()):
        if to_pos is None:
            _ixs_to = near
        else:
            to_close |= close_dict[to_pos]
            _ixs_to = near - to_close
        if not _ixs_to:
            return {} # failed no reachable positions
        to_pos = random.choice(tuple(_ixs_to))
        out_dict[id] = to_pos
    return out_dict

if __name__ == '__main__':
    simulate(near_dict, close_dict)
随机导入
将numpy作为np导入
从numba导入类型,jit
从numba.typed导入Dict,列表
n_位置=100
位置覆盖率=10
最小距离=5
n_id=5
near_dict={x:set(范围(x,x+位置覆盖))
如果x
转换为Numba: 这是一个乏味的问题,因为Numba施加了许多限制。当然最好是一步一步地发布这段代码,但是答案太长了。
简而言之,要将代码转换为Numba并使用
nopython
进行充分优化,您需要大致遵循以下规则。
免责声明:我不是numba专家,本节仅以观察为基础:

  • 除了基本对象和numpy之外,没有对象。这意味着没有集合和字典
  • 函数只能返回单个值,不能返回数组
  • 所有的东西都需要输入,或者要让Numba自动推断出类型
可能还有更多。我不太确定。因此,基本上就像名字所暗示的那样,如果你选择nopython路线,忘记你使用的是python。代码要么需要非常简单(就像在几个简单计算的循环中一样),要么你将不得不对代码进行修改以使其被遗忘。(或者还有其他一些技巧我还没有发现。)
编辑:我发现了一个诀窍-numba现在支持字典,即使在nojit中,只要您事先声明所有类型。它还支持集合。但是它不能在字典中存储集合,因此在您的情况下,您必须先将集合存储在数组中,然后使用字典作为从id到in的转换表不是不可能,但绝对不是直截了当的

这段代码很可能是有效的。但是其中的一部分被弃用了,因为我放弃了尝试摆脱最后一段
[]
,转而使用numpy数组。此外,它没有经过优化,也没有对性能进行测量

import random
import numpy as np
from numba import jit
n_positions = 100
position_coverage = 10
min_dist = 5
n_ids = 5
near_keys = random.sample(range(n_positions), n_ids)


@jit(nopython=True)
    def simulate(near_keys):
    to_pos = -1
    _ixs_to = np.zeros(1)
    to_return = []
    for id in sorted(near_keys, key=lambda x: random.random()):
        if id < n_positions:
            near = np.arange(id, id + position_coverage)
        else:
            near = np.arange(id, n_positions)

        print(id, near)
        if to_pos == -1:
            _ixs_to = near
        else:
            to_close = []
            a = int(n_positions - position_coverage + min_dist)
            to_pos = int(to_pos)
        if to_pos < a:
            pos_values = np.arange(to_pos, to_pos + min_dist)
        else:
            pos_values = np.arange(to_pos, n_positions)

        for i in pos_values:
            if not i in to_close:
                to_close.append(i)

        _ixs_to = np.zeros(1, dtype=np.int64)
        for i in near:
            if not i in to_close:
                _ixs_to = np.append(_ixs_to, i)
        if _ixs_to[0] == 0:
            _ixs_to = _ixs_to[1:]

        if _ixs_to.ndim == 0:
            return [-1] # failed no reachable positions
        np.random.rand()
        to_pos = np.random.choice(_ixs_to)
        to_return.append(id)
        to_return.append(to_pos)
        return to_return

if __name__ == '__main__':
    print(simulate(near_keys))
随机导入
将numpy作为np导入
从numba导入jit
n_位置=100
位置覆盖率=10
最小距离=5
n_id=5
near_keys=random.sample(范围(n_位置),n_id)
@jit(nopython=True)
def模拟(近_键):
to_pos=-1
_ixs_to=np.零(1)
to_return=[]
对于排序中的id(在_键附近,key=lambda x:random.random()):
如果id
那么,如果代码不必要地复杂,那么您的相当好的代码又发生了什么呢

首先,我用生成函数替换了集:
near_dict={x:set(范围(x,x+位置覆盖))如果x

变成

def get_接近(x):
如果x
然后,我以一种不需要它们的方式重写了集合的并集和差集。这是通过迭代数组并检查要删除或添加的值来完成的。注意,这是最重要的部分
def get_near(x):
    if x < n - position_coverage:
        return set(range(x, x + position_coverage))
    else:
        return set(range(x, n_positions)