Blue Flower

Клеточные автоматы

Для нашей окончательной архитектуры мы собираемся использовать совершенно другой подход. Все агенты, которые мы создавали до сих пор, были «нисходящими» . Центральный, интеллектуальный агент принимает решения и выполняет планы. Но что, если мы перевернем это с ног на голову?

 

Вдохновленная сложными природными системами архитектура клеточных автоматов использует огромное количество простых децентрализованных агентов, работающих в сети.

 

Единого контроллера нет. Вместо этого, разумное общее поведение достигается за счет многократного применения простых локальных правил.

 

В крупномасштабной системе искусственного интеллекта это узкоспециализированный, но невероятно мощный подход для пространственного мышления, моделирования и оптимизации.

 

Представьте себе планирование логистики, моделирование заболеваний или моделирование роста городов. Это превращает само проблемное пространство в «вычислительную структуру», которая решает задачи посредством волнообразного распространения информации.

 

Это может быть очень сложно, но давайте попробуем разобраться, как это работает?

 

 

 

 

Клеточные автоматы (созданы)

Фарид Хан

)

Инициализация сетки: Создается сетка из «ячеек-агентов», каждая из которых имеет простой тип (например, OBSTACLE, EMPTY) и состояние (например, значение).

Установка граничных условий: Целевой ячейке присваивается специальное состояние для начала вычислений (например, ее значение устанавливается равным 0).

Синхронный тик: В каждом «тике» каждая клетка одновременно вычисляет свое следующее состояние, основываясь только на текущем состоянии своих непосредственных соседей.

Возникновение: По мере работы системы информация распространяется по сетке подобно волне, создавая градиенты и пути.

Стабилизация состояния: система работает до тех пор, пока изменения в сети не прекратятся, то есть вычисления не будут завершены.

Считывание данных: Решение считывается непосредственно из конечного состояния сетки.

В основе этой системы лежат CellAgentи WarehouseGrid. У CellAgentимеется одно простое правило: мое новое значение равно 1 + the minimum value of my non-obstacle neighbors.

 10:40:59


class CellAgent : 

    """Единственный агент в нашей сетке. Его единственная задача — обновлять свое значение на основе соседей.""" 

    def __init__ ( self, cell_type: str ): 

        self. type = cell_type # 'EMPTY', 'OBSTACLE', 'PACKING_STATION', etc.

         self.pathfinding_value = float ( 'inf' ) 

 

def update_value ( self, neighbors: List [ 'CellAgent' ] ): 

        """Основное локальное правило.""" 

        if self. type == 'OBSTACLE' : return float ( 'inf' ) 

        min_neighbor_value = min ([n.pathfinding_value for n in neighbors]) 

        return min (self.pathfinding_value, min_neighbor_value + 1 ) 

 

 

class WarehouseGrid : 

    def __init__ ( self, layout ): 

        self.h, self.w = len (layout), len (layout[ 0 ]) 

        self.grid = np.array([[self._cell(ch) for ch in row] for row in layout], dtype= object ) 

 

    def _cell ( self, ch ): 

        return CellAgent( 'EMPTY' ) if ch== ' ' else \ 

               CellAgent( 'OBSTACLE' ) if ch== '#' else \ 

               CellAgent( 'PACKING_STATION' ) if ch== 'P' else CellAgent( 'ПОЛКА' ,item=ch) 

 

    def neighbors ( self,r,c ): 

        return [self.grid[nr,nc] for dr,dc in [( 0 , 1 ),( 0 ,- 1 ),( 1 , 0 ),(- 1 , 0 )] 

                if 0 <=(nr:=r+dr)<self.h and 0 <=(nc:=c+dc)<self.w] 

 

    def tick ( self ):

        vals = np.array([[cell.update_value(self.neighbors(r,c)) 

                          for c,cell in enumerate (row)] for r,row in enumerate (self.grid)]) 

        changed= False 

        for r,row in enumerate (self.grid): 

            for c,cell in enumerate (row): 

                if cell.pathfinding_value!=vals[r,c]: changed= True

                 cell.pathfinding_value=vals[r,c] 

        return changed 

 

    def visualize ( self,show= False ): 

        t=Table(show_header= False ) 

        [t.add_column() for _ in range (self.w)] 

        sy={ 'EMPTY' : '·' , 'OBSTACLE' : '█' , 'PACKING_STATION' : 'P' } 

        for r in range (self.h): 

            row=[] 

            for c in range (self.w): 

                cell,val=self.grid[r,c],self.grid[r,c].pathfinding_value 

                if show and val!= float ( 'inf' ): 

                    col= 255 -(val* 5 )% 255

                     row.append( f"[rgb( {col} , {col} , {col} )] { int (val):^ 3 } [/]" ) 

                else : 

                    row.append(sy.get(cell. type ,cell.item)) 

            t.add_row(*row) 

        console. print (t)

 

 

 

 

 

Сотовый подход (создан)

Теперь мы можем реализовать высокоуровневую логику, которая использует эту вычислительную структуру для поиска пути. Функция propagate_path_waveустанавливает целевое значение (например, упаковочную станцию) равным 0, а затем позволяет сетке работать tickдо тех пор, пока значения пути не распределятся по всему складу.

 

def propagate_path_wave ( grid: WarehouseGrid, target_pos: Tuple [ int , int ] ): 

    """Сбрасывает и затем запускает симуляцию до тех пор, пока значения поиска пути не стабилизируются.""" 

    # Сбрасываем все значения поиска пути до бесконечности 

    for cell in grid.grid.flatten(): cell.pathfinding_value = float ( 'inf' ) 

    # Устанавливаем значение цели равным 0, чтобы начать волну

     grid.grid[target_pos].pathfinding_value = 0 

    

    while grid.tick(): # Продолжаем тикать, пока сетка не стабилизируется 

        pass

Давайте создадим схему расположения товаров на складе и укажем ей найти путь от товара «А» до упаковочной станции «P».

 

warehouse_layout = [ 

    "#######" , 

    "#A #" , 

    "# ### #" , 

    "# # #" , 

    "# # # #" , 

    "# P #" , 

    "#######" , 

 

grid = WarehouseGrid(warehouse_layout) 

packing_station_pos = grid.item_locations[ 'P' ] 

propagate_path_wave(grid, packing_station_pos)

 

 

Вся магия в том, что мы не рассчитывали путь. Сетка вычислила кратчайший путь от каждого квадрата до упаковочной станции одновременно. В результате получился красивый градиент, обтекающий препятствия.

 

 

 

Числа обозначают расстояние до точки «P». Чтобы найти путь от точки «A», агенту достаточно начать движение из её местоположения (значение 8) и всегда двигаться к соседней точке с наименьшим числом (7, затем 6 и т. д.). Он просто следует по уклону вниз.

 

Шаг 1: Выполните пункт «А»                      

┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ 

┃ 🌊 Расчет траектории движения от упаковочной станции...                    

┃ 🚚 Найден путь для товара А. Движение вдоль градиента...                

┃ Путь: (3, 0) -> (3, 1) -> (3, 2) -> (4, 2) -> (5, 2) -> (5, 3)     

┃ ✅ Товар «А» перемещен на упаковочную станцию.                  

┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ 

 

Шаг 2: Выполните пункт 'B'                      

┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ 

┃ 🌊 Вычисление траектории движения от упаковочной станции...                    

┃ 🚚 Найден путь для предмета B. Движение вдоль градиента...                

┃ Путь: (4, 5) -> (4, 4) -> (4, 3) -> (5, 3)                        

┃ ✅ Товар 'B' перемещен на упаковочную станцию.                  

┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ 

 

Заказ на товары A и B успешно выполнен. Товар А был извлечен с полки в точке с координатами (3, 0) и перемещен по 6-шаговому маршруту к упаковочной станции. Затем товар В был извлечен из точки (4, 5) и перемещен по 4-шаговому маршруту к тому же месту назначения. Пол склада теперь свободен и готов к приему следующего заказа.

Наш агент начинает думать, это совершенно другой способ мышления агентов. Рассуждения распределены по всей системе.

 

Чтобы это формализовать, наш магистр права, выступающий в роли судьи, не может оценивать «решение», но он может оценивать сам процесс .

 

 

class EmergentBehaviorEvaluation (BaseModel): 

    optimality_score: int = Field (description= "Оценка от 1 до 10, гарантирующая ли эмергентный процесс нахождение оптимального решения." ) 

    robustness_score: int = Field (description= "Оценка от 1 до 10, определяющая способность системы адаптироваться к изменениям в окружающей среде." ) 

    justification: str = Field (description= "Краткое обоснование оценок." )

 

 

По результатам оценки, этот процесс заслуживает высшей оценки за свою надежность.

 

--- Оценка процесса клеточного автомата ---

 { 

    'optimality_score' : 7 , 

    'robustness_score' : 8 , 

    'justification' : "Процесс системы является одновременно оптимальным и устойчивым. Метод распространения волн представляет собой разновидность поиска в ширину, что гарантирует кратчайший путь. Кроме того, решение возникает из локальных правил, то есть, если добавляется препятствие, повторный запуск моделирования автоматически найдет новый оптимальный путь без каких-либо изменений в основном алгоритме."

 }

Хотя это очень специализированная область…

 

Клеточные автоматы могут быть чрезвычайно эффективны для решения определенных задач, например, когда нам необходимо предложить параллельный и адаптируемый способ обработки сложных пространственных задач.