У мене є колекція обчислювальних моделей, які можна було б охарактеризувати як асинхронні стільникові автомати. Ці моделі нагадують модель Ізінга, але трохи складніші. Схоже, що такі моделі виграють від запуску на графічному процесорі, а не на процесорі. На жаль, паралелізувати таку модель не зовсім просто, і мені зовсім не зрозуміло, як це робити. Я знаю, що є література з цього приводу, але все це, здається, спрямоване на хардкорних комп'ютерних вчених, які цікавляться деталями алгоритмічної складності, а не на когось, як я, хто просто хоче опис чогось, що я можу реалізувати, і тому я вважаю це досить непроникним.
Для наочності я не шукаю оптимального алгоритму настільки, як щось, що я можу швидко реалізувати в CUDA, що, ймовірно, дасть значне прискорення над моєю реалізацією процесора. Час програміста є набагато більш обмежуючим фактором, ніж час роботи комп'ютера в цьому проекті.
Я також повинен уточнити, що асинхронний стільниковий автомат - це зовсім інша річ, ніж синхронний, і методи паралелізації синхронних КА (наприклад, життя Конвея) не можуть бути легко адаптовані до цієї проблеми. Різниця полягає в тому, що синхронний СА оновлює кожну клітинку одночасно на кожному кроці, тоді як асинхронний оновлює випадкову обрану локальну область на кожному кроці, як зазначено нижче.
Моделі, які я хочу паралелізувати, реалізовані на решітці (зазвичай гексагональній), що складається з ~ 100000 комірок (хоча я хотів би використовувати більше), а непаралелізований алгоритм їх запуску виглядає приблизно так:
Виберіть сусідню пару комірок навмання
Обчисліть "енергетичну" функцію на основі локальної околиці, що оточує ці клітини
Імовірно, що залежить від (з параметром β ), або поміняйте стани двох комірок, або не зробіть нічого.
Повторіть описані вище кроки нескінченно.
Існують також деякі ускладнення, пов'язані з граничними умовами, але я думаю, що це не складе великих труднощів для паралелізації.
Варто зазначити, що мене цікавить тимчасова динаміка цих систем, а не просто стан рівноваги, тому мені потрібно щось, що має еквівалентну динаміку до вищевказаного, а не просто щось, що наближатиметься до такого ж рівноважного розподілу. (Отже, варіанти алгоритму шахматної дошки - це не те, що я шукаю.)
Основна складність паралелізації вищевказаного алгоритму - зіткнення. Оскільки всі розрахунки залежать лише від локальної області решітки, для багатьох решітних сайтів можна паралельно оновлюватись до тих пір, поки їхні квартали не перетинаються. Питання в тому, як уникнути таких перекриттів. Я можу придумати декілька способів, але не знаю, який із них найкращий для реалізації. Це такі:
Використовуйте центральний процесор для створення списку випадкових сітчастих сайтів та перевірки на колізії. Коли кількість сайтів сітки дорівнює кількості процесорів GPU або якщо виявлено зіткнення, надішліть кожен набір координат до блоку GPU, щоб оновити відповідний сайт сітки. Це було б легко здійснити, але, ймовірно, не дало б великої швидкості, оскільки перевірка на предмет зіткнень на процесорі, ймовірно, не буде набагато дешевшою, ніж все оновлення на процесорі.
Розділіть решітку вгору на регіони (по одній на одиницю GPU) і мати один блок GPU, відповідальний за випадковий вибір і оновлення комірок сітки в її регіоні. Але є багато проблем з цією ідеєю, яку я не знаю, як вирішити, найбільш очевидним є те, що саме повинно відбутися, коли підрозділ вибирає околиці, що перекриваються краю свого регіону.
Апроксимуйте систему так: нехай час протікає дискретно. Розділіть решітку вгору на іншунабір регіонів на кожному кроці часу відповідно до деякої заздалегідь визначеної схеми, і кожен блок GPU випадковим чином вибирає та оновлює пару комірок сітки, сусідство яких не перекриває межу регіону. Оскільки межі змінюються щоразу на етапі, це обмеження може не надто впливати на динаміку, якщо регіони є відносно великими. Це здається простим у здійсненні та, ймовірно, швидким, але я не знаю, наскільки добре це наблизить динаміку, або яка найкраща схема вибору меж регіону на кожному кроці часу. Я знайшов деякі посилання на "блок-синхронні стільникові автомати", які можуть бути або не збігатися з цією ідеєю. (Я не знаю, бо, здається, що всі описи методу є російською мовою або є джерелами, до яких я не маю доступу.)
Мої конкретні питання такі:
Чи є один із перерахованих вище алгоритмів розумним способом підходу до паралелізації GPU асинхронної моделі CA?
Чи є кращий спосіб?
Чи існує код бібліотеки для такого типу проблем?
Де я можу знайти чіткий англомовний опис методу «блок-синхрон»?
Прогрес
Я вважаю, що я придумав спосіб паралелізації асинхронного СА, який може бути відповідним. Алгоритм, описаний нижче, призначений для звичайного асинхронного СА, який оновлює лише одну клітинку за один раз, а не сусідню пару клітин, як це робить моя. Є деякі проблеми з узагальненням цього мого конкретного випадку, але я думаю, що я маю ідею, як їх вирішити. Однак я не впевнений, яку перевагу від швидкості вона дасть із причин, обговорених нижче.
Ідея полягає в заміні асинхронного СА (відтепер ACA) на стохастичний синхронний CA (SCA), який веде себе рівномірно. Для цього спочатку уявляємо, що ACA - це процес Пуассона. Тобто час протікає безперервно, і кожна комірка є постійною ймовірністю за одиницю часу виконання своєї функції оновлення, незалежно від інших комірок.
- параметр, значення якого можна вибрати довільно.)
На кожному логічному кроці часу осередки SCA оновлюються наступним чином:
Я вважаю, що це гарантує, що осередки будуть оновлюватися в порядку, який можна "розшифрувати", щоб відповідати початковому ACA, уникаючи зіткнень та дозволяючи паралельно оновлювати деякі комірки. Однак через першу точку кулі вище, це означає, що більшість процесорів GPU будуть працювати в режимі очікування на кожному кроці SCA, що є менш ніж ідеальним.
Мені потрібно ще трохи подумати про те, чи можна покращити продуктивність цього алгоритму та як розширити цей алгоритм для вирішення випадку, коли декілька комірок оновлюються одночасно в ACA. Однак це виглядає багатообіцяюче, тому я подумав, що опишу його тут на випадок, якщо хто-небудь (а) знає щось подібне в літературі, або (б) може запропонувати будь-яке розуміння цих решти питань.
exp()
), тому я б не подумав, що має сенс розподіляти його по декількох потоках. Я думаю, що краще (і простіше для мене) спробувати і оновити кілька пар паралельно, по одній парі на нитку.