Вопрос или проблема
Я реализую моделирование динамики системы, где у меня есть частицы 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
, что не всегда является эффективным для частого удаления и добавления элементов. Вот несколько рекомендаций по улучшению:
-
Используйте динамические массивы:
Вместо того чтобы использовать стандартный массив, задумайтесь о реализации динамического массива (или списка), который будет управлять своим размером самостоятельно. Вы можете использовать встроенные структуры данных, такие какList
, в Mathematica, так как они уже оптимизированы для подобных операций. -
Избегайте частых модификаций:
Вместо того чтобы каждый раз вызыватьDelete
иJoin
, можно использовать два списка:- Один для активных (существующих) частиц.
- Другой для "освобожденных" частиц, которые будут добавлены в активный список позже. Это позволит вам минимизировать количество операций с массивами.
-
Пакетная обработка изменений:
Когда вы добавляете или удаляете частицы, делайте это за один проход. Например, вместо непосредственного удаления и добавления в каждом цикле, собирайте индексы для удаления и добавления, а затем применяйте изменения после завершения всех вычислений. -
Оптимизация генерации новых частиц:
При создании новых частиц, возможно, стоит создать их в одном массиве и затем объединить с активными частицами, а не по отдельности увеличивая массив.
Перепишем ваш код с учетом этих рекомендаций:
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
используется для итерации над временем, что упрощает и улучшает читаемость кода.
Ваша реализация должна работать быстрее за счет минимизации количества операций по изменению размера массива. Это, в свою очередь, приведет к уменьшению времени выполнения ваших симуляций.