简体   繁体   English

递归地执行多次自我回避行走

[英]Executing multiple self-avoiding walks, recursively

I have a 3D simple cubic lattice, which I call Grid in my code, with periodic boundary conditions of size 20x20x20 (number are arbitrary).我有一个 3D 简单立方晶格,我在代码中将其称为Grid ,其周期性边界条件为 20x20x20(数字是任意的)。 What I want to do is plant multiple polymer chains with a degree of polymerization N (graphs with N nodes) that do no overlap, are self-avoiding.我想要做的是种植多个聚合度为 N 的聚合物链(具有 N 个节点的图)不重叠,是自我避免的。

At the moment, I can plant one polymer recursively.目前,我可以递归地种植一种聚合物。 This is my code这是我的代码

const std::vector <int> ex{1,0,0}, nex{-1,0,0}, ey{0,1,0}, ney{0,-1,0}, ez{0,0,1}, nez{0,0,-1};     // unit directions 
const std::vector <std::vector <int>> drns = {ex, nex, ey, ney, ez, nez};                           // vector of unit directions 

void Grid::plant_polymer(int DoP, std::vector <std::vector <int>>* loc_list){
    // loc_list is the list of places the polymer has been 
    // for this function, I provide a starting point 
    if (DoP == 0){
        Polymer p (loc_list); 
        this->polymer_chains.push_back(p); // polymer_chains is the attribute which holds all polymer chains in the grid 
        return; // once the degree of polymerization hits zero, you are done
    }; 

    // until then 
    // increment final vector in loc_list in a unit direction 
    std::vector <int> next(3,0); 
    for (auto v: drns){

        next = add_vectors(&((*loc_list).at((*loc_list).size()-1)), &v);
        
        impose_pbc(&next, this->x_len, this->y_len, this->z_len); 
        
        
        if (this->occupied[next]==0){ // occupied is a map which takes in a location, and spits out if it is occupied (1) or not (0)
// occupied is an attribute of the class Grid
            dop--; // decrease dop now that a monomer unit has been added 
            (*loc_list).push_back(next); // add monomer to list 
            this->occupied[next] == 1; 
            return plant_polymer(DoP, loc_list); 
        } 
    }


    std::cout << "no solution found for the self-avoiding random walk...";
    return; 

This is not a general solution.这不是一个通用的解决方案。 I am providing a seed for the polymer, and also, I am only planting one polymer.我正在为聚合物提供种子,而且,我只种植一种聚合物。 I want to make it such that I can plant multiple polymers, without specifying a seed.我想让它可以种植多种聚合物,而无需指定种子。 Is it possible to recursively hunt for a starting position, every time I want to add a polymer, and then build a polymer while making sure it is not overlapping with other polymers already in the system?每次我想添加聚合物时,是否可以递归地寻找起始位置,然后构建聚合物,同时确保它不与系统中已有的其他聚合物重叠? Any advice you have would be appreciated.您的任何建议将不胜感激。

Self-avoiding walks has been studied at least since the 1960s and there's a vast literature on them.至少自 1960 年代以来,人们一直在研究自我避免的步行,并且有大量关于它们的文献。 Fortunately, the problem you face belong to the simplest ones (walks' length is fixed at a relatively small value).幸运的是,您面临的问题属于最简单的问题(步行长度固定在一个相对较小的值)。

1 1

The first thing you should be aware of is that your question is too broad to have a unique answer.您应该注意的第一件事是,您的问题太宽泛,无法给出唯一的答案。 That is, if you plant many polymers in the system, the result you're going to get depends on the dynamics of the polymer planting and growing.也就是说,如果您在系统中种植许多聚合物,您将获得的结果取决于聚合物种植和生长的动态。 There are two major cases.主要有两种情况。 Either you plant a number of seeds and start growing polymers from them, or you grow each polymer "elsewhere" and then try to plant them in the system at a random location, one by one, keeping the condition of self-avoidance.要么种植许多种子并开始从中生长聚合物,要么在“其他地方”种植每种聚合物,然后尝试将它们一一种植在系统中的随机位置,保持自我回避的状态。 The two methods will result in statistically different distributions of polymers, and there's nothing you can do about it, except to specify the system dynamics in more detail.这两种方法将导致聚合物在统计上不同的分布,除了更详细地指定系统动力学外,您无能为力。

I believe the second approach is a bit easier, as it saves you from deciding what to do if some polymers cannot grow to the desired length (restart the simulation?), so let's focus just on it.我相信第二种方法更容易一些,因为如果某些聚合物不能长到所需的长度(重新开始模拟?),它可以让您不必决定该怎么做,所以让我们只关注它。

The general algorithm might look like this:一般算法可能如下所示:

  • Set maximum_number_of_attempts to reasonably large, but not too large a value, say a millionmaximum_number_of_attempts设置为相当大,但不是太大的值,比如一百万
  • Set required_number_of_polymers to the required valuerequired_number_of_polymers设置为所需的值
  • Set number_of_attempts to 0number_of_attempts设置为 0
  • Set number_of_planted_polymers to 0number_of_planted_polymers设置为 0
  • While number_of_attempts < maximum_number_of_attempts AND number_of_planted_polymers < required_number_of_polymers虽然number_of_attempts < maximum_number_of_attempts AND number_of_planted_polymers < required_number_of_polymers
    • increase number_of_attempts by 1number_of_attempts增加 1
    • generate the next random polymer生成下一个无规聚合物
    • chose a random position (lattice site) in the system在系统中选择一个随机位置(晶格位置)
    • check if the polymer can be planted at this position without intersections检查聚合物是否可以在该位置种植而没有交叉点
    • if and only if yes,当且仅当是,
      • accept the polymer (add it to the list of polymers; update the list of occupied lattice nodes)接受聚合物(将其添加到聚合物列表中;更新占用的晶格节点列表)
      • increase number_of_planted_polymers by 1number_of_planted_polymers增加 1

To speed thing up, you can be choosing the initial positions only from unoccupied sites (eg in a while loop).为了加快速度,您可以仅从未占用的站点中选择初始位置(例如,在while循环中)。 Another idea is to try and use a polymer, on its first plating failure, several times (but not too many, you'd need to experiment) at different positions.另一个想法是尝试使用聚合物,在第一次电镀失败时,在不同的位置多次(但不要太多,你需要试验)。

2 2

Now the next step: how to generate a self-avoiding random walk.现在下一步:如何生成一个自我避免的随机游走。 Your code is almost OK, except for a few misconceptions.您的代码几乎没问题,除了一些误解。

In function void Grid::plant_polymer there's one grave error: it always performs the search in the space of possible polymer shapes in exactly the same order .在函数void Grid::plant_polymer中有一个严重的错误:它总是以完全相同的顺序在可能的聚合物形状的空间中执行搜索。 In other words, it is deterministic.换句话说,它是确定性的。 For Monte Carlo methods it sounds like a disaster.对于蒙特卡洛方法来说,这听起来像是一场灾难。 One thing you might do to handle it is to randomly shuffle the directions.您可能会做的一件事是随机改变方向。

  auto directions = drns;
  std::shuffle(begin(directions), end(directions), random_generator); // c++17
  for (const auto & v: directions)
  {
    ...

For this to work, you'll need a random number generator already defined and initialized, eg为此,您需要一个已经定义和初始化的随机数生成器,例如

    std::random_device rd;
    std::mt19937 random_generator(rd());

somewhere much earlier, and only once, in the program.在程序中更早的地方,并且只有一次。

If you don't use C++17, use std::random_shuffle instead of std::shuffle , but be warned that the latter has been depreciated, see https://en.cppreference.com/w/cpp/algorithm/random_shuffle for the discussion why.如果您不使用 C++17,请使用std::random_shuffle而不是std::shuffle ,但请注意后者已被贬值,请参阅https://en.cppreference.com/w/cpp/algorithm/ random_shuffle讨论为什么。


As a side remark, when asking a specific software-related question, please try and provide a Minimal, reproducible example .附带说明一下,当询问与软件相关的特定问题时,请尝试提供一个最小的、可重现的示例 Answering questions based only on reading code is almost always more time-consuming, and the answers tend to be more sketchy and less accurate.仅基于阅读代码回答问题几乎总是更耗时,而且答案往往更粗略且不太准确。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM