簡體   English   中英

遞歸地執行多次自我回避行走

[英]Executing multiple self-avoiding walks, recursively

我有一個 3D 簡單立方晶格,我在代碼中將其稱為Grid ,其周期性邊界條件為 20x20x20(數字是任意的)。 我想要做的是種植多個聚合度為 N 的聚合物鏈(具有 N 個節點的圖)不重疊,是自我避免的。

目前,我可以遞歸地種植一種聚合物。 這是我的代碼

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; 

這不是一個通用的解決方案。 我正在為聚合物提供種子,而且,我只種植一種聚合物。 我想讓它可以種植多種聚合物,而無需指定種子。 每次我想添加聚合物時,是否可以遞歸地尋找起始位置,然后構建聚合物,同時確保它不與系統中已有的其他聚合物重疊? 您的任何建議將不勝感激。

至少自 1960 年代以來,人們一直在研究自我避免的步行,並且有大量關於它們的文獻。 幸運的是,您面臨的問題屬於最簡單的問題(步行長度固定在一個相對較小的值)。

1

您應該注意的第一件事是,您的問題太寬泛,無法給出唯一的答案。 也就是說,如果您在系統中種植許多聚合物,您將獲得的結果取決於聚合物種植和生長的動態。 主要有兩種情況。 要么種植許多種子並開始從中生長聚合物,要么在“其他地方”種植每種聚合物,然后嘗試將它們一一種植在系統中的隨機位置,保持自我回避的狀態。 這兩種方法將導致聚合物在統計上不同的分布,除了更詳細地指定系統動力學外,您無能為力。

我相信第二種方法更容易一些,因為如果某些聚合物不能長到所需的長度(重新開始模擬?),它可以讓您不必決定該怎么做,所以讓我們只關注它。

一般算法可能如下所示:

  • maximum_number_of_attempts設置為相當大,但不是太大的值,比如一百萬
  • required_number_of_polymers設置為所需的值
  • number_of_attempts設置為 0
  • number_of_planted_polymers設置為 0
  • 雖然number_of_attempts < maximum_number_of_attempts AND number_of_planted_polymers < required_number_of_polymers
    • number_of_attempts增加 1
    • 生成下一個無規聚合物
    • 在系統中選擇一個隨機位置(晶格位置)
    • 檢查聚合物是否可以在該位置種植而沒有交叉點
    • 當且僅當是,
      • 接受聚合物(將其添加到聚合物列表中;更新占用的晶格節點列表)
      • number_of_planted_polymers增加 1

為了加快速度,您可以僅從未占用的站點中選擇初始位置(例如,在while循環中)。 另一個想法是嘗試使用聚合物,在第一次電鍍失敗時,在不同的位置多次(但不要太多,你需要試驗)。

2

現在下一步:如何生成一個自我避免的隨機游走。 您的代碼幾乎沒問題,除了一些誤解。

在函數void Grid::plant_polymer中有一個嚴重的錯誤:它總是以完全相同的順序在可能的聚合物形狀的空間中執行搜索。 換句話說,它是確定性的。 對於蒙特卡洛方法來說,這聽起來像是一場災難。 您可能會做的一件事是隨機改變方向。

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

為此,您需要一個已經定義和初始化的隨機數生成器,例如

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

在程序中更早的地方,並且只有一次。

如果您不使用 C++17,請使用std::random_shuffle而不是std::shuffle ,但請注意后者已被貶值,請參閱https://en.cppreference.com/w/cpp/algorithm/ random_shuffle討論為什么。


附帶說明一下,當詢問與軟件相關的特定問題時,請嘗試提供一個最小的、可重現的示例 僅基於閱讀代碼回答問題幾乎總是更耗時,而且答案往往更粗略且不太准確。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM