橘智橘智
FakeOrange
预计阅读时间:3分钟35秒

随机扩散搜索入门(Stochastic Diffusion Search, SDS)

SDS引入了一种全新的基于概率的多智能体方法,用以寻找全局最优解。

0
0

前言



本文属于搬运内容,原作者:Leon Fedden (Salute!)原文链接在文章末尾!


欢迎来到本周关于“受自然启发的算法”系列的文章。以下是前几周的内容链接:





本周的完整代码(基于C++和openFrameworks库)可以在GitHub仓库中找到。



什么是随机扩散搜索(SDS)?



随机扩散搜索(Stochastic Diffusion Search, SDS)属于群体智能算法的大家族。与许多其他受自然启发的算法不同,SDS已经建立了一种数学框架,证明了它具有以下两个特性:


  • 收敛性:在足够的时间和计算资源条件下可以达到全局最优解。


  • 线性时间复杂度:在搜索效率方面表现出色。


SDS 引入了一种全新的基于概率的多智能体方法,用以寻找全局最优解。



SDS核心概念:两种隐喻



在 SDS 算法中,有两种高层次的比喻来形象化地描述其机制:


  • 采矿隐喻(Mining)


  • 餐馆隐喻(Restaurants)


本文选取了采矿隐喻来介绍这一算法,并配以对应的代码说明:



采矿隐喻



一群矿工发现附近的山丘中蕴藏着丰富的金矿(全局最优解)。这些贪婪的淘金矿工各自冥思苦想,并随机地提出一个假设,猜测某座山中可能藏有金矿。这些山包含多个潜在的挖掘点,而矿工会随机选择其中一个(即山可以被分割成多个局部搜索区域)。


一天中,矿工们会前往选定的挖掘点,并检查他们的假设是否正确。这个过程称为测试阶段(Test Phase)


下面是代码实现的核心片段:


for (auto& agent : agents)
{
    if (agent->set_happy(partial_grid))
    {
        happy_agents.push_back(agent);
        const size_t hill_index = get_hill_index((*agent), partial_size, grid_size);

        if (++most_frequent_hill_indices[hill_index] > max_indices)
        {
            max_indices = most_frequent_hill_indices[hill_index];
            best_index = hill_index;
        }
    }
    else
        unhappy_agents.push_back(agent);
}

best_hill_coordinates = get_hill_position(best_index, partial_size, grid_size, draw_scalar);



代码解析


  • 智能体的状态更新


  • 记录最佳区域


  • 更新全局最优解



采矿隐喻的下一步:扩散阶段(Diffusion Phase)



到了晚上,矿工们齐聚当地的酒馆,一边喝酒一边热烈讨论谁找到了金矿。每个未找到金矿的矿工都会感到沮丧,他们会随机问其他矿工是否在自己的山上找到了金矿。


  • 如果对方找到了金矿并且感到满意,那么沮丧的矿工会选择该山上的某个随机位置提出新的假设。


  • 如果对方也是沮丧的矿工,他们决定完全随机地在新位置上尝试寻找金矿。


这一部分的搜索过程称为扩散阶段(Diffusion Phase)。以下是代码实现的核心逻辑:


for (auto& agent : unhappy_agents)
{
    if (happy_agents.size() > 0)
    {
        size_t random_index = uniform_random.get_next(agent_size - 1);
        if (agents[random_index]->happy)
        {
            set_agent_randomly_in_same_quadrant(agents[random_index],
                                                agent,
                                                agents,
                                                partial_grid,
                                                partial_size,
                                                grid_size,
                                                uniform_random);
        }
        else
        {
            agent->x = uniform_random.get_next(grid_size - 1);
            agent->y = uniform_random.get_next(grid_size - 1);
        }
    }
    else
    {
        agent->x = uniform_random.get_next(grid_size - 1);
        agent->y = uniform_random.get_next(grid_size - 1);
    }
}


data/78df2c1f-e442-415d-a382-fa7925af0c4b/e0392c92-c515-460d-8879-cb2c35105723image.png


代码解析


  • 扩散策略对于所有“不开心”的智能体(矿工),他们会随机与其他智能体互动:若找到“开心”的智能体:则将自己随机地调整到相同山丘的某一区域中。若遇到另一个“不开心”的智能体:则完全随机地在新的网格位置生成一个假设。


  • 当没有“开心”的智能体存在时所有“不开心”的智能体都会完全随机地选择一个新位置进行搜索。



测试阶段与扩散阶段的循环



**测试阶段(Test Phase)扩散阶段(Diffusion Phase)**会被反复执行,直到找到解决方案为止。



终止条件



SDS 的退出或终止策略较为灵活,以下是常见的几种方式:


  • 手动中断不设置任何终止条件,由用户手动中止算法。这通常适用于问题空间动态变化或没有预定义模式的情况。


  • 基于时间的终止条件设置时间或迭代次数的上限,算法在达到上限时自动停止。


  • 基于聚类的终止条件通过跟踪稳定聚类的形成,当群体智能体聚集到某个稳定的区域后,停止搜索。



动态问题空间中的随机扩散搜索



当解空间随着时间变化时,问题的复杂性会显著增加。以下展示的是一个经过修改的 SDS,在由**三维柏林噪声(Perlin Noise)**生成的阈值化问题空间上运行的示例。需要注意的是,SDS 只能在给予足够时间的情况下保证找到全局最优解,而对于每一帧来说,算法显然没有足够的时间!


data/78df2c1f-e442-415d-a382-fa7925af0c4b/fdcd637a-a05a-42a8-9268-339601575ae1image.png



动态问题空间的挑战



在动态问题空间中,智能体可能会过度开发某个已经确定的山丘,即便有更好的山丘或解出现。为了解决这一问题,可以通过引入**上下文敏感机制(Context Sensitive Mechanism)**对算法进行改进,以释放资源并增强搜索的探索性。



上下文敏感机制的改进



该机制的核心思想:智能体的假设复制


这一机制有效防止智能体集中在同一个区域,促进了更全面的探索。



动手尝试



想要进一步研究 SDS 的动态行为?可以下载代码并亲自动手试试!代码行数不多,上手非常容易。


感谢阅读! 😊


希望本篇文章让你对随机扩散搜索有了更深入的理解。如果有任何问题或想法,欢迎留言讨论!



原文链接

评论