Разработка высокопроизводительного конечного автомата на Java

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

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

Рекомендации

  1. Сгенерированные автоматы обычно не массивны. (~ 100-500 состояний).
  2. Однако реализация должна иметь возможность масштабирования.
  3. Реализация должна позволять быстрые преобразования (минимизация, детерминация и т. Д.).
  4. Планируется внедрить DFA, NFA, GNFA, PDA и, возможно, Tree Automata. Надеюсь, в рамках единого интерфейса, если это возможно.
  5. Должен быть хороший баланс между использованием памяти и производительностью.

Текущие вопросы относительно дизайна для меня:

  1. Следует ли определять классы для State, Symbol и Transition? Или следует использовать «скрытую» внутреннюю структуру. Лично я считаю, что использование классов как таковых будет тратить много памяти, поскольку ту же информацию можно хранить в гораздо более сжатой форме. Но дает ли это возможность более быстрых преобразований? Есть ли другие плюсы / минусы?

  2. Как лучше всего хранить данные внутри? Использование таких структур данных, как HashMap и HashSet, позволяет осуществлять поиск с амортизированной постоянной продолжительностью, но при этом возникает элемент накладных расходов. Это лучший способ? Хранение информации о переходах в виде примитивного (или нет) массива, похоже, тратит довольно много памяти. Особенно, когда библиотеке нужно обрабатывать много автоматов одновременно. Каковы плюсы и минусы различных структур данных?

Я ценю любой вклад. Спасибо!


person Nico Huysamen    schedule 12.03.2011    source источник
comment
Привет, может быть, ты можешь использовать мою реализацию профессора в качестве справочника. Он основан на DFA и NFA и имеет открытый исходный код. Реализация: brics.dk/automaton Тесты производительности: tusker.org/regex/regex_benchmark.html   -  person Lasse Espeholt    schedule 12.03.2011
comment
@lasseespeholt - Лол, на самом деле у меня уже есть код, и я работаю над ним. Это одна из немногих библиотек Java, которые я обнаружил, которые действительно находятся в активной разработке. Выражаю признательность и привет вашему профессору!   -  person Nico Huysamen    schedule 12.03.2011
comment
Вы думали об использовании сеансов правил с отслеживанием состояния в Drools?   -  person Chris J    schedule 12.03.2011


Ответы (2)


Ну, как быстро вы хотите, чтобы это было? Код на brics.dk/automaton действительно объявляет свои собственные классы State и Transition, хотя, очевидно, их можно переписать с использованием примитивов (черт возьми, состояние всего класса Transition, очевидно, легко поместится на long).

Дело в том, что если вы переместите, например, класс Transition в простой примитив, тогда вам больше не придется использовать медленные HashMap<Transition,...> коллекции Java по умолчанию: вы можете использовать библиотеки, такие как TLongObjectHashMap от Trove (или _5 _... или TLongLong, что угодно), который владеет HashMap по умолчанию большим временем (библиотеки Trove в основном предоставляют карты и наборы, которые очень эффективны, как быстрые, так и маленькие, когда вы работаете с примитивами: вы не генерируете бесчисленный мусор или константу ненужное обертывание примитивов, поэтому меньше GC и т. д. Если вам нужна производительность, тогда вам стоит проверить Trove ... И их предстоящий выпуск 3.0 на 20% быстрее, чем Trove 2.0).

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

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

static int next_id;
.
.
.
id = next_id++;

и этот конструктор вызывается из ... 90 разных мест!

Пример из учебника, как не создавать уникальный идентификатор в многопоточном сценарии (черт возьми, даже сделать next_id volatile недостаточно, скажем, вы хотите AtomicInteger здесь). Я недостаточно хорошо знаю библиотеку, но эта штуковина с идентификаторами кажется мне очень подозрительной.

person SyntaxT3rr0r    schedule 12.03.2011
comment
Спасибо за информацию, особенно в Trove, я обязательно взгляну на нее. Что касается скорости, то чем быстрее, тем лучше, если это не влияет на скорость преобразования. - person Nico Huysamen; 12.03.2011
comment
Я играл с Trove. Эти коллекции безумно быстрые. Спасибо за ссылку! - person Nico Huysamen; 13.03.2011
comment
@Nico Huysamen: ах, хорошо :) То, как они генерируются, тоже довольно круто: они в основном используют препроцессор / генераторы кода, чтобы не дублировать Java-код для всех примитивных типов. - person SyntaxT3rr0r; 15.03.2011

У меня есть несколько вопросов:

  • Какая часть должна быть быстрой: ввод FSA, построение FSA или выполнение FSA?

  • Откуда поступает ввод FSA? Человек вводит состояния и дуги или какой-то автоматический процесс? Приходит ли реальный ввод из регулярного выражения, которое преобразовано в FSA?

  • Как часто можно менять FSA? Раз в секунду? Раз в год?

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

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

person Mike Dunlavey    schedule 12.03.2011
comment
1) Что на самом деле должно быть быстрым, так это любые преобразования, выполняемые в автоматах (определение, минимизация и т. Д.). 2) 99,9% генерируется случайным генератором. 3) Если вы говорите о трансформациях, я бы сказал чаще, чем раз в год. - person Nico Huysamen; 13.03.2011
comment
@Nico: Тогда я бы создал прототип этих алгоритмов преобразования на простейшей возможной структуре данных. Настройте их на реалистичный ввод. Затем выполните версию 2 с любым структура данных, которую вы теперь знаете, лучше всего. - person Mike Dunlavey; 13.03.2011
comment
Я забыл упомянуть. Я не хочу преобразовывать регулярные выражения в FA (ну, я тоже сделаю это, но не сначала). При генерации случайных FA мне нужен полный контроль над количеством состояний, переходов, количеством переходов на состояние и т. Д. Простое преобразование REGEX сделает это требование недействительным. - person Nico Huysamen; 13.03.2011