Расчеты эволюции на C# - Применение библиотеки

ОГЛАВЛЕНИЕ

Применение библиотеки

При создании библиотеки главной идеей было придание ей гибкости и многоразовости, что позволяет применять ее для решения разных задач. Код библиотеки не зависит ни от какой конкретной задачи, но реализует общие принципы расчетов эволюции и таких алгоритмов, как генетические алгоритмы, генетическое программирование и программирование выражений генов. Такие сущности расчета эволюции, как популяция, хромосомы, методы селекции и функции пригодности, реализованы в виде отдельных классов, что облегчает их объединение для решения конкретной задачи. В большинстве случаев пользователю библиотеки необходимо лишь определить функцию пригодности для своей задачи, а затем определить тип хромосомы, алгоритм селекции и ряд других параметров, таких как размер популяции, частота мутации и кроссовера, и т.д. Если конкретная задача требует специфических вариантов хромосом или генетических операторов мутации и кроссовера, пользователь может создать собственный класс хромосомы, реализовав интерфейс IChromosome или унаследовав от одного из уже имеющихся классов хромосом. То же самое касается методов селекции и функций пригодности – если требуется специальный алгоритм селекции или функция пригодности, надо создать класс, реализующий интерфейс ISelectionMethod или IFitnessFunction, соответственно. После создания любых пользовательских классов, реализующих определенные выше интерфейсы, эти классы будут работать со всеми остальными классами библиотеки, расширяя ее и позволяя решать специфические задачи.

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

Оптимизация функции

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

// определить функцию оптимизации
public class UserFunction : OptimizationFunction1D
{
    public UserFunction( ) :
        base( new DoubleRange( 0, 255 ) ) { }

    public override double OptimizationFunction( double x )
    {
        return Math.Cos( x / 23 ) * Math.Sin( x / 50 ) + 2;
    }
}
...
// создать генетическую популяцию
Population population = new Population( 40,
    new BinaryChromosome( 32 ),
    new UserFunction( ),
    new EliteSelection( ) );
// запустить одну эру популяции
population.RunEpoch( );

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

Символическая регрессия (приближение)

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

Код для решения задачи похож на вышеприведенный код. Используется тот же класс популяции и тот же класс метода селекции. Единственное отличие – функция пригодности, что очевидно, потому что задача и класс хромосомы другие. Для решения задачи можно использовать класс GPTreeChromosome – если надо применить метод генетического программирования, или класс GEPChromosome – если надо применить метод программирования выражений генов.

// приближаемая функция
double[,] data = new double[5, 2] {
    {1, 1}, {2, 3}, {3, 6}, {4, 10}, {5, 15} };
// создать популяцию
Population population = new Population( 100,
    new GPTreeChromosome( new SimpleGeneFunction( 6 ) ),
    new SymbolicRegressionFitness( data, new double[] { 1, 2, 3, 5, 7 } ),
    new EliteSelection( ),
    0.1 );
// запустить одну эру популяции
population.RunEpoch( );

В примере выше приближаемая функция определяется с двумерным массивом пар (X, Y). Еще одна любопытная особенность примера выше – последний аргумент конструктора класса Population – значение указывает, что 10% из новой генерации будет состоять из новых случайных хромосом, но 90% будут лучшими членами текущей генерации.