Общие советы по алгоритму работы с массивами переменного размера [закрыто]

Вопрос или проблема

Я реализую моделирование динамики системы, где у меня есть частицы X и что-то еще. При моделировании динамики пара частиц X может исчезать или, наоборот, может появляться пара частиц X. Частьца X параметризована n=8 действительными числами.

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

Код написан на Mathematica, но скомпилирован на C++. Внутри я использую команды Delete и Join, которые, соответственно, удаляют строки и добавляют их.

Кажется, что это не самое оптимальное решение. У вас есть идеи, как улучшить эту часть алгоритма?

Ниже представлен мой код:

table = RandomReal[{0, 1}, {10^3, 8}];

evolutionToy = 
 Compile[{{table, _Real, 2}, {Niterations, _Integer}}, 
  Module[{table1, evolution = 0., counterint = 0, len, i1 = 0, i2 = 0},
   table1 = table;
   While[counterint <= Niterations,
    counterint++;
    evolution = RandomReal[{0, 1}];
    len = Length[table1];
    i1 = RandomInteger[{1, len}];
    i2 = i1;
    While[i2 == i1, i2 = RandomInteger[{1, len}]];
    If[evolution < 1/3,
     table1[[i1]] = RandomReal[{0, 1}, 8];
     table1[[i2]] = RandomReal[{0, 1}, 8];
     ,
     If[evolution < 2/3,
      table1 = Delete[table1, {{i1}, {i2}}];
      ,
      table1 = Join[table1, RandomReal[{0, 1}, {2, 8}]];
      ]
     ];
    ];
   table1
   ], CompilationTarget -> "C", RuntimeOptions -> "Speed", 
  RuntimeAttributes -> {Listable}];
table = RandomReal[{0, 1}, {10^4, 8}];
evolutionToy[table, 10^3]; // AbsoluteTiming

{0.0370318,Null}

Здесь evolution, а также замены на список случайных действительных чисел, являются тривиальной версией некоторых реальных вычислений.

Ответ или решение

Чтобы оптимизировать вашу реализацию алгоритма с переменной длиной массива частиц в Mathematica, следует рассмотреть несколько аспектов, связанных с представлением данных и выполнением операций над массивами. Ваш текущий подход использует команды Delete и Join, что не всегда является эффективным для частого удаления и добавления элементов. Вот несколько рекомендаций по улучшению:

  1. Используйте динамические массивы:
    Вместо того чтобы использовать стандартный массив, задумайтесь о реализации динамического массива (или списка), который будет управлять своим размером самостоятельно. Вы можете использовать встроенные структуры данных, такие как List, в Mathematica, так как они уже оптимизированы для подобных операций.

  2. Избегайте частых модификаций:
    Вместо того чтобы каждый раз вызывать Delete и Join, можно использовать два списка:

    • Один для активных (существующих) частиц.
    • Другой для "освобожденных" частиц, которые будут добавлены в активный список позже. Это позволит вам минимизировать количество операций с массивами.
  3. Пакетная обработка изменений:
    Когда вы добавляете или удаляете частицы, делайте это за один проход. Например, вместо непосредственного удаления и добавления в каждом цикле, собирайте индексы для удаления и добавления, а затем применяйте изменения после завершения всех вычислений.

  4. Оптимизация генерации новых частиц:
    При создании новых частиц, возможно, стоит создать их в одном массиве и затем объединить с активными частицами, а не по отдельности увеличивая массив.

Перепишем ваш код с учетом этих рекомендаций:

table = RandomReal[{0, 1}, {10^3, 8}];

evolutionToy = 
  Compile[{{table, _Real, 2}, {Niterations, _Integer}}, 
   Module[{activeParticles = table, toRemove = {}, toAdd = {}, evolution = 0.},
    Do[
     evolution = RandomReal[{0, 1}];
     len = Length[activeParticles];
     i1 = RandomInteger[{1, len}];
     i2 = RandomInteger[{1, len}];
     While[i2 == i1, i2 = RandomInteger[{1, len}]];

     If[evolution < 1/3,
      activeParticles[[i1]] = RandomReal[{0, 1}, 8];
      activeParticles[[i2]] = RandomReal[{0, 1}, 8],
      If[evolution < 2/3,
       AppendTo[toRemove, {i1, i2}],
       AppendTo[toAdd, RandomReal[{0, 1}, {2, 8}]];
      ];
     ];

     (* Удаление и добавление разом *)
     If[Length[toRemove] > 0,
      activeParticles = Delete[activeParticles, toRemove];
      toRemove = {};
     ];
     If[Length[toAdd] > 0,
      activeParticles = Join[activeParticles, toAdd];
      toAdd = {};
     ];
     ,
     {counterint, 1, Niterations}
    ];
    activeParticles
   ], CompilationTarget -> "C", RuntimeOptions -> "Speed", 
   RuntimeAttributes -> {Listable}];

table = RandomReal[{0, 1}, {10^4, 8}];
evolutionToy[table, 10^3]; // AbsoluteTiming

Пояснения к коду:

  • Введены два отдельных списка: toRemove и toAdd. Это позволяет всего лишь один раз изменять массив частиц после завершения всех действий, что значительно повышает эффективность.
  • Функция Do используется для итерации над временем, что упрощает и улучшает читаемость кода.

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

Оцените материал
Добавить комментарий

Капча загружается...