Чи можливо ефективно зображувати мутацію об'єкт-графіка з незмінними станами?


12

Я практикую використання незмінного об'єкта в C ++. Моя особиста мета - представити загальний графік об'єктів (в купі) із послідовністю незмінних графіків.

Побудувати графік з декількома версіями не так вже й складно. Проблема - продуктивність. Версія з грубою силою потребує повної копії графіка, і це було не прийнятно.

Я намагався ділитися незмінними вузлами. Але в цьому випадку у мене з’явилася нова проблема; посилання. Посилання на інший об'єкт має бути оновлено у цілому графіку. Для цього потрібно відвідувати всі вузли щоразу, коли я отримую нову версію графіка. І це мутує вузли з посиланнями, тому їх також слід отримати (копіюючи). Продуктивність не буде кращою, ніж копіювання з грубої сили.

Наскільки я можу собі уявити, немає реального ефективного способу представити мутацію об'єктного графіка з незмінними станами. Тож я прошу якусь ідею з цього приводу.

Чи можливо ефективно зображувати мутацію об'єктного графіка з незмінним станом?


1
Це важко лише тому, що ви накладаєте краї на вузли. Якщо ви зберегли краї зовні, в незмінній колекції, це було б легко.
dan_waterworth

@dan_waterworth Якщо я використовую список суміжності, мені потрібно шукати кожен край кожного разу. Тож я думаю, що це компроміс між продуктивністю читання та запису.
Еоніль

1
Це не повинно бути списком.
dan_waterworth

@dan_waterworth Ви маєте на увазі щось на кшталт B-tree?
Еоніл

2
широкі дерева, як B-дерева, як правило, використовуються, коли затримка до середовища зберігання висока. У цьому випадку вам може бути краще щось вужче, але так, якесь збалансоване дерево пошуку було б хорошою ідеєю.
dan_waterworth

Відповіді:


11

Те, що ви шукаєте, називається стійкою структурою даних. Канонічним ресурсом для стійких структур даних є книга Кріса Окасакі « Чисто функціональні структури даних» . Стійкі структури даних останнім часом викликали інтерес завдяки їх популяризації в Clojure та Scala.

Однак, чомусь незрозумілі причини, стійкі графіки, як правило, ігноруються. У нас є списки, десятки різних видів дерев, масивів, черги з пріоритетністю, карти, але графіків немає.

Я дійсно знайшов лише один папір: Повністю стійкі графіки - яку вибрати?


4

Якщо ви не вважаєте, що з'єднання між об’єктами є частиною вашого перетвореного ресурсу (і ви, можливо, у цьому випадку наступне, ймовірно, не дуже допомагає), ви можете розглянути питання про розділення об'єктів на частину, яка представляє частину зв'язку об'єкта та частини, яка являє собою незмінний стан.

Тоді ви могли б мати, щоб кожен з об'єктів підключення містив вектор перетворених станів. Таким чином, ви можете працювати з номером версії графа, щоб отримати доступ до відповідного незмінного стану.

Щоб уникнути необхідності переходу всього графіка кожного разу, коли відбувається оновлення певного вузла, ви можете зробити так, що якщо доступ до вузла з номером версії перевищує поточний номер версії, використовується поточна версія . Якщо вузол оновлюється, ви заповнюєте всі проміжні версії з попередньою версією - таким чином, ви можете робити ледачі оновлення на графіку об'єкта.

Якщо зв'язок між об'єктами є частиною вашого стану, то вищесказане не працює. Але, можливо, ви можете продовжити це так:

Для кожного об'єкта в графіку створіть "обробляти об'єкт". Об'єкт ручки містить перелік змінних незмінних станів. Замість того, щоб зберігати посилання на об'єкти в будь-якому з об'єктів графіка, ви б зберігали посилання на об'єкт обробки. Тоді кожне посилання на об'єкти буде переоформлено через ручку, використовуючи ручку та номер версії перегляду графіку об'єкта, який наразі обробляється. Це поверне правильний незмінний стан для об'єкта. Незмінні стани використовують ручки для посилання на інші об'єкти в графіку, тому ви завжди отримуєте послідовну дату для версії графа, яку ви хочете обробити.

Ця ж логіка, описана вище, стосується оновлення версій в ручках - що дозволяє ліниві, локалізовані оновлення.


3

Існує опубліковане рішення цієї проблеми з дуже хорошою амортизованою часовою складністю, але її важко знайти, коли ти не знаєш, що саме шукати. Ви можете знайти хороший підсумок у цих конспектах лекцій (перевірте розділ 2.2.3) або прочитайте оригінальний документ Зробити стійкі структури даних . Якщо ваш об’єктний графік має обмежену зв’язок (наприклад, деревоподібні структури), ви навіть можете досягти амортизованої складності O (1) як для читання, так і для оновлення незмінного графіка, що вражає.

Ідея полягає в тому, що кожен об’єкт, окрім збереження свого поточного незмінного стану, залишає простір для запису змін. Коли ви хочете створити новий незмінний графік із існуючого, застосувавши зміни, ви повинні врахувати два випадки:

  • Об'єкт, який ви хочете змінити, все ще має місце для змін. Ви можете зберігати зміни безпосередньо в об’єкті.

  • Об'єкт не має більше місця для змін. Ви створюєте новий екземпляр на основі поточних значень та порожніх записів змін. Тепер вам потрібно рекурсивно оновлювати всі об'єкти, на які посилається старий об'єкт, на посилання на новий об’єкт.

    Якщо в самому об'єкті посилання є ще простір для змін, ви можете зберігати зміни в посиланні безпосередньо, інакше він каскадується рекурсивно.

Хоча ця схема підтримує ефективне створення нових поколінь графіків незмінних об'єктів, це ускладнює читання з неї, оскільки тепер вам потрібно вказати, до якої "версії" ви хочете отримати доступ, читаючи дані з незмінного об'єкта. Це пояснюється тим, що незмінний об'єкт може містити інформацію для декількох версій через збережені записи змін, тому вам потрібно вказати, яку версію потрібно переглянути.

Реалізуючи це, я намагаюся приховати цю складність в API. Посилаючись на щось із незмінного графіка ззовні, я використовую генеровані заглушки замість прямих посилань, тому абонентам не потрібно продовжувати передавати потрібну версію вручну. Це робить посилання трохи дорожчими, ніж прямий вказівник, але я вважаю, що це варто для зручності.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.