Московский государственный университет путей сообщения
Опубликован: 10.10.2014 | Доступ: свободный | Студентов: 866 / 193 | Длительность: 22:10:00
Лекция 6:

Генетическое программирование

6.10 Модульное построение программ в генетическом программировани

Эволюционный подход в представленном выше виде порождает слабо структурированные программы, что подтверждают приведенные примеры. Напротив, программист (человек) при проектировании программ, как правило, применяет модульный принцип построения, где решение разбивается на отдельные небольшие (часто используемые) участки кода, которые затем используются в разработке программы. Для этого широко используется аппарат функций и подпрограмм, что позволяет существенно упростить как процесс проектирования, так и сами разрабатываемые программы. Этот подход является типичным примером применения стратегии "разделяй и властвуй", которая широко используется при проектировании программ.

Таблица 6.13.
Параметры Значения
Цель: Вывод третьего закона Кеплера, аппроксимируюшей данные табл.6.12
Терминальное множество Переменная r(расстояние от солнца в астрономических единицах)
Функциональное множество +, - , * ,^ , sqrt, \sin, \cos
Фитнесс-функция Сумма абсолютных значений разности между реальным периодом и даваемым текущей формулой
Мощность популяции: 500
Вероятность кроссинговера: 0.80
Вероятность мутации: 0.05
Максимальное число поколений: 50

Одним из самых перспективных направлений повышения эффективности ГП является использование модульного принципа, в котором идентифицируются некоторые функциональные единицы программы, которые оформляются по определенным стандартам и сохраняются для дальнейшего использования.

Модулем называют последовательность (соседних) операторов программы, ограниченную некоторыми окаймляющими элементами, который имеет общий идентификатор. Модуль должен обладать, по крайней мере, следующими свойствами:

  1. логическая замкнутость;
  2. реализация по принципу "черного ящика";
  3. должен иметь интерфейс для взаимодействия с другими модулями (множество операций и типов данных).

Модульный принцип является средством инкапсуляции блоков кода. Такие блоки оформляются в виде подпрограмм, которые затем могут многократно использоваться в главной программе или включаться в другие подпрограммы. Это позволяет существенно уменьшить сложность программы за счет оформления часто используемых идентичных участков кода в виде подпрограмм. Отметим, что меньшая сложность (длина) программ способствуют их "выживанию" в процессе эволюционного поиска. В ГП используется различная техника для реализации модульного принципа. Самыми известными методами являются автоматически определяемые функции (АОФ) (automatically defined functions –ADF), которые введены в [2] и детально исследованы во многих работах [2,5].

ADF построены по аналогии с функциями языка LISP. Поэтому программа, содержащая ADF, также представляется древовидной структурой, но при этом дерево состоит из двух частей (поддеревьев):

  1. главной программы, которая, прежде всего, оценивается с помощью фитнесс-функции;
  2. определение функций. Пример такой структуры приведен на рис.6.21.

Эти два поддерева соответствуют структуре программы на языке программирования высокого уровня, подобном С++, Паскаль и т.п., где главная программа (тело) сопровождается "объявлениями", где описаны соответствующие функции. Отметим, что обе указанные компоненты должны участвовать в эволюции, которая в этом случае производит программу, построенную в соответствии с модульным принципом.

На рис.6.21 корень дерева"программа" соответствует программе в целом и объединяет ее различные части. Узел "определение" является корневым для поддерева, содержащего описание функции ADF0. В случае необходимости использования нескольких функций каждой из них необходимо выделить соответствующее поддерево ADF для описания функции.

Дерево, содержащее ADF

Рис. 6.21. Дерево, содержащее ADF

Левая ветвь, исходящая из узла "определение", содержит имя функции (ADF0), которое включается в функциональное множество главной программы и используется для вызова соответствующей функции. Справа от узла имени расположен узел, представляющий список аргументов данной функции. Этот список определяет имена входных переменных аргументов функции. Эти имена входят в терминальное множество тела соответствующей функции. Этот подход аналогичен определению функции в С++ или Паскале, где необходимо дать имя функции и определить входные переменные вместе с описанием тела функции. Следует отметить, что использование рекурсии, как правило, не допускается вследствие значительных трудностей реализации.

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

До запуска программы поиска с использованием данного подхода необходимо определить число ADF функций и допустимое число аргументов для каждой функции. То есть мы должны в каком-то смысле задать структуру дерева. Естественно, при инициализации мы должны придерживаться этой структуры. При этом различные поддеревья (главная программа и функции) генерируются независимо (случайными методами).

При использовании данного подхода необходимо дополнительно выполнить следующие действия:

  1. выбрать число функций ADF;
  2. фиксировать число аргументов для каждой ADF;
  3. определить возможные связи между разными ADF, если используется больше одной функции;
  4. определить терминальные функциональные множества для главной программы и ADF;
  5. определить фитнесс- функцию для оценки особей;
  6. определить параметры эволюционного алгоритма.

Основным недостатком данного подхода является необходимость определения заранее структуры программы, которая включает число ADF функций, число аргументов и т.п.

Кроме ADF в ГП применяются и другие методы модульного построения программ [5]. К ним относится использование автоматически определяемых макросов (automatically defined macros), автоматическое определение циклов do while, until и рекурсии, применение сложных и абстрактных типов данных и т.д. С одной стороны они позволяют получать более компактные программы, но с другой их применение существенно осложняет сам процесс их построения.