Какой метод кроссовера следует использовать для скрещивания выражений Postfix в генетическом алгоритме?

Я создаю проект, основная цель которого - найти заданное число (если возможно, в противном случае возможно ближайшее), используя 6 заданных чисел и основные операторы (+, -, *, /). Идея состоит в том, чтобы случайным образом генерировать выражения, используя заданные числа и операторы, в обратной шлифованной (постфиксной) нотации, потому что я нашел ее проще всего генерировать и вычислять позже. Эти выражения являются Индивидуумами в Популяции моего Генетического Алгоритма. Эти выражения имеют форму ArrayList of Strings в Java, где Strings являются как операторами, так и операндами (указанными числами).

Главный вопрос здесь заключается в том, как лучше всего объединить этих людей (фактически, постфиксные выражения)? Прямо сейчас я думаю о перекрестных выражениях, составленных из всех шести заданных операндов (и 5 операторов с ними). Позже я, вероятно, также буду скрещивать выражения, которые будут состоять из меньшего количества операндов (5, 4, 3, 2 и тоже только 1), но я думаю, что я должен сначала разобраться с этим, как с самым сложным случаем (если вы думаю, было бы лучше начать по-другому, я открыт для любых предложений). Итак, дело в том, что каждое выражение составляется из всех заданных операндов, а также в дочернее выражение должны быть включены все операнды. Я понимаю, что для этого требуется своего рода упорядоченный кроссовер (часто используемый в таких задачах, как TSP), и я много читал об этом (например, здесь, где описаны несколько методов), но я не совсем понял, какой из них будет лучше в моем случае (я также знаю, что в Genetic Algorithms есть много методом проб и ошибок, но я говорю о другом).

То, что я говорю, беспокоит меня, это операторы. Если бы у меня был только список операндов, то не было бы проблемой пересечь 2 таких списка, например, взяв случайный подмассив половинных элементов из 1 родителя, и заполнить остальные оставшимися элементами из родителя 2, сохраняя порядок, например это было. Но вот если я, скажем, возьму первую половину выражения из первого родительского выражения, мне обязательно придется заполнить дочернее выражение оставшимися операндами, но что мне делать с операторами? Возьмите их из родителя 2, как и остальные операнды (но тогда мне придется остерегаться, потому что для использования оператора в постфиксном выражении мне нужно иметь как минимум еще 1 операнд, и проверка этого все время может занять много времени, или нет?), или, может быть, я мог бы сгенерировать случайные операторы для остальной части дочернего выражения (но тогда это не было бы чистым пересечением, не так ли)?

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

Итак, это в значительной степени суммирует мою проблему. Как я уже сказал, главный вопрос заключается в том, как выполнить пересечение, но если у вас есть какие-либо другие предложения или вопросы по программе (возможно, более простое представление выражений, кроме списка строк, что может быть проще/быстрее для пересечения, может быть, что-то, что я не сделал не упоминать здесь, это не имеет значения, может быть, даже совершенно новый подход к проблеме?), я хотел бы их услышать. Я не дал здесь никакого кода, потому что не думаю, что он нужен для ответа на этот вопрос, но если вы считаете, что это поможет, я обязательно отредактирую, чтобы решить эту проблему. Еще раз, главный вопрос в том, чтобы ответить, как пересечь эту конкретную часть проблемы (ожидается идея или псевдокод, хотя сам код тоже был бы хорош :D), но если вы считаете, что мне нужно изменить что-то еще, или вы знаете какие-то другие решения всей моей проблемы, не стесняйтесь говорить.

Заранее спасибо!


person Urke    schedule 15.08.2017    source источник


Ответы (1)


На ум приходят два подхода:

Подход №1

Закодируйте каждый геном как выражение фиксированной длины, где нечетные индексы — это числа, а четные — операторы. Для мутации вы можете немного изменить числа и/или изменить операторы.

Плюсы:

  • Очень просто кодировать

Минусы:

  • Придется создать парсер инфиксов
  • Выражения фиксированной длины

Подход №2

Закодируйте каждый геном в виде синтаксического дерева. Например, 4 + 3 / 2 - 1 эквивалентно Add(4, Subtract(Divide(3, 2), 1)), что выглядит так:

   _____+_____
   |         |
   4     ____-____
         |       |
       __/__     1
       |   |
       3   2

Затем при переходе выберите случайный узел из каждого дерева и поменяйте их местами. Для мутации вы можете добавлять, удалять и/или изменять случайные узлы.

Плюсы:

  • Может найти лучшие результаты
  • Выражения переменной длины

Минусы:

  • Добавляет временную сложность
  • Добавляет сложность программирования

Вот пример второго подхода:

Кроссовер на деревьях

Источник

person ljeabmreosn    schedule 15.08.2017
comment
Спасибо за краткий ответ, мне нравится, как вы написали плюсы и минусы для обоих подходов. Я понимаю, что было сделано в этом примере в конце, но загвоздка в том, что операнды должны оставаться прежними, так что просто поменять местами часть выражения в большинстве случаев будет недостаточно. Кроме того, мне нравится этот синтаксис дерева, и я, вероятно, буду думать таким образом с этого момента. - person Urke; 16.08.2017
comment
@Urke Если я вас правильно понял, вам дается 6 число, а также вы можете использовать +, -, * и /, аналогично этой игры. Итак, если вы решили использовать метод синтаксического дерева, все операнды будут листьями дерева. Вы хотите сказать, что операторы фиксированы (по порядку) и вам нужно найти наилучшую перестановку чисел? - person ljeabmreosn; 16.08.2017
comment
@Ijeabmreosn Еще раз спасибо за ваш ответ, я полностью его понимаю. Прямо сейчас я надеюсь услышать другое мнение, надеюсь, новый ответ на этот вопрос, потому что я хотел бы все обдумать, прежде чем углубляться в него. - person Urke; 16.08.2017