Детерминированный алгоритм дендритных клеток — Deterministic Dendritic Cell Algorithm (dDCA)
Содержание
Введение
В данной работе предлагается адаптация Deterministic Dendritic Cell Algorithm для задач непрерывной оптимизации. Оригинальный dDCA применяется для обнаружения аномалий. Основная идея — переосмысление иммунологических концепций в терминах поиска.
Дендритные клетки становятся агентами, исследующими пространство решений. Сигналы опасности и безопасности отражают качество найденных решений. Механизм созревания определяет баланс между исследованием новых областей и эксплуатацией перспективных регионов. Предложенный подход сохраняет ключевые особенности оригинального dDCA — детерминированное распределение времени жизни, централизованную обработку сигналов и формулы расчёта контекста — адаптируя их для навигации в многомерном пространстве поиска.
Иммунная система человека — одна из наиболее эффективных адаптивных систем, созданных природой. Особый интерес среди её компонентов представляют дендритные клетки — специализированные клетки врождённого иммунитета. Они патрулируют ткани, накапливают сигналы из окружающей среды и принимают решения о характере обнаруженных объектов. Эта способность к интеграции разнородной информации легла в основу алгоритма дендритных клеток (Dendritic Cell Algorithm, DCA), предложенного Greensmith и коллегами в 2005 году.
Теоретическим фундаментом DCA служит Теория Опасности, сформулированная P. Matzinger в 1994 году. В отличие от классической парадигмы «своё-чужое», эта теория утверждает, что иммунная система реагирует не на чужеродность объекта, а на сигналы опасности от повреждённых клеток. Это объясняет толерантность к полезным бактериям кишечника (чужие, но безопасные) и аутоиммунные реакции (свои, но опасные).
Детерминированная версия алгоритма (dDCA), разработанная J. Greensmith and U. Aickelin в 2008 году, устранила стохастические элементы оригинала, обеспечив воспроизводимость результатов.
Реализация алгоритма
Дендритные клетки циркулируют по тканям организма, собирая два типа сигналов:
- Сигналы опасности (Danger, D) — молекулы, выделяемые повреждёнными или умирающими клетками. Представьте дым или звук разбитого стекла — это явные признаки проблемы.
- Сигналы безопасности (Safe, S) — молекулы, характерные для нормального функционирования тканей. Можно описать спокойной музыкой и обычным шумом толпы в торговом центре.
После накопления достаточного количества сигналов, дендритная клетка «созревает» и мигрирует в лимфоузел, где передаёт собранную информацию T-лимфоцитам. Критически важно, чтобы клетка созревала в одном из двух состояний:
- Зрелая (Mature) — если преобладали сигналы опасности. Такая клетка активирует иммунный ответ.
- Полузрелая (Semi-mature) — если преобладали сигналы безопасности. Такая клетка способствует толерантности.
Классическая иммунология учила, что иммунная система различает «своё» и «чужое». Однако это не объясняет многих явлений: почему бактерии в кишечнике не вызывают иммунного ответа (они чужие), а раковые клетки организм часто игнорирует (они свои)? Теория Опасности предлагает иной взгляд: иммунная система реагирует не на чужеродность, а на опасность. Главный вопрос не «Это своё или чужое?», а «Это опасно или безопасно?».
Простой пример: занозу в пальце организм воспринимает как угрозу не потому, что дерево «чужое», а потому, что повреждённые клетки вокруг занозы выделяют сигналы опасности. Те же молекулы дерева в виде бумаги, которую мы держим в руках, не вызывают реакции —нет повреждения, нет сигналов опасности.
Для адаптации dDCA к задачам оптимизации необходимо установить соответствие между иммунологическими и оптимизационными понятиями:
| Иммунология | Оптимизация |
|---|---|
| Дендритная клетка | Агент поиска |
| Антиген (исследуемый объект) | Кандидатное решение |
| Сигнал опасности D | Индикатор плохого качества |
| Сигнал безопасности S | Индикатор хорошего качества |
| Созревание в Mature | Переход к локальному поиску |
| Созревание в Semi-mature | Переход к глобальному поиску |
| Время жизни клетки | Период накопления статистики |
Ключевая идея адаптации: качество решения определяет баланс сигналов D и S. Хорошие решения генерируют больше сигналов безопасности, плохие — больше сигналов опасности. Накопив статистику за несколько итераций, агент «понимает», находится ли он в перспективном регионе (стоит исследовать локально) или в бесперспективном (стоит переместиться в другое место).
Представьте, что вы ищете лучший ресторан в незнакомом городе. У вас есть команда из 50 друзей, каждый исследует свой район. Друг, попавший в район с хорошими ресторанами, получает положительные сигналы: приятные запахи, довольные посетители, высокие рейтинги в витринах. Он накапливает «безопасные» впечатления и решает исследовать этот район подробнее — заглянуть в соседние переулки, попробовать разные заведения поблизости.
Друг, оказавшийся в промышленной зоне, получает негативные сигналы: нет ресторанов, пустые улицы, неприятные запахи. Он накапливает «опасные» впечатления и решает покинуть этот район — переехать в совершенно другую часть города. Важно, что решение принимается не мгновенно, а после накопления опыта. Один плохой ресторан в хорошем районе не заставит вашего друга уехать. Аналогично, один случайно найденный приличный ресторан в плохом районе не означает, что весь район перспективен.
Каждый агент (дендритная клетка) характеризуется набором параметров Агент i:
- c[i] — текущая позиция (кандидатное решение)
- f[i] — значение фитнес-функции
- lifespan — оставшееся время жизни
- k_acc — накопленный контекст
- iterations — количество пройденных итераций
Одна из ключевых особенностей dDCA — детерминированное назначение времени жизни клеткам. В отличие от случайного распределения, время жизни назначается равномерно:
lsi = i × lsmax / N, i = 1, 2, …, N; где N — размер популяции, lsmax — максимальное время жизни.
Пример. При N = 50 и lsmax = 20:
- Агент 1: время жизни = 0.4
- Агент 10: время жизни = 4.0
- Агент 25: время жизни = 10.0
- Агент 50: время жизни = 20.0
Это обеспечивает равномерное распределение моментов созревания во времени. В любой момент часть агентов только начала накапливать информацию, часть находится в середине цикла, а часть готова принять решение. Такая асинхронность может повысить устойчивость алгоритма.
На каждой итерации для каждого агента вычисляются сигналы на основе нормализованной приспособленности:
fnorm = (fi − fmin) / (fmax − fmin); где fmin и fmax — минимальное и максимальное значения фитнеса в текущей популяции.
Важно: предполагается задача минимизации. Агент с fnorm = 0 имеет лучшее решение в популяции, агент с fnorm = 1 - худшее. Сигналы опасности и безопасности: Di = fnorm × 50 Si = (1 − fnorm) × 50. Интерпретация: агент с худшим решением (fnorm = 1) получает D = 50, S = 0 - максимум опасности. Агент с лучшим решением (fnorm = 0) получает D = 0, S = 50 - максимум безопасности. Коэффициент 50 выбран для удобства: сумма сигналов всегда равна 100, что упрощает интерпретацию.
Контекст и созревание. Выходной сигнал (контекст) определяет характер созревания:
ki = Di − ws × Si; где ws — вес безопасного сигнала (по умолчанию 2.0).
| fnorm | D | S | k (при ws = 2) | Интерпретация |
|---|---|---|---|---|
| 0.0 | 0 | 50 | −100 | Лучший агент, сильно отрицательный k |
| 0.33 | 16.5 | 33.5 | −50.5 | Хороший агент |
| 0.67 | 33.5 | 16.5 | 0.5 | Порог: k становится положительным |
| 1.0 | 50 | 0 | 50 | Худший агент, максимальный k |
При ws = 2 порог находится на уровне fnorm = 2/3 ≈ 0.67. Это означает, что только худшие 33% популяции имеют положительный контекст.
Контекст накапливается на протяжении жизни агента: kacc = kacc + ki; k̄ = kacc / iterations. Среднее значение k̄ сглаживает случайные флуктуации и даёт устойчивую оценку качества региона.
Стратегии перемещения. После вычисления накопленного контекста агент выбирает одну из трёх стратегий перемещения.
1. Локальная мутация (Mature). Если k̄ > 0, агент находится в перспективном регионе и выполняет локальный поиск: cnew = cold + μ × range × rand(−1, 1), где μ — коэффициент мутации (0.01), range — размах области поиска. Аналогия: вы нашли хороший район с ресторанами, теперь вы не уезжаете далеко, а обходите соседние улицы в поисках ещё лучшего заведения.
2. Направленное перемещение (Semi-mature, вариант 1). Если k̄ ≤ 0, агент склонен к исследованию.
С вероятностью (1 − preinit) выполняется направленное перемещение к лучшему известному решению: cnew = cold + r × (cbest − cold) + noise, где r ∈ [0, 1] — случайный коэффициент. Аналогия: ваш район оказался неудачным, но друг сообщил об отличном ресторане в другой части города, и вы движетесь в том направлении, попутно осматривая окрестности.
3. Глобальная реинициализация (Semi-mature, вариант 2). С вероятностью preinit = min(|k̄| / 50, 0.5) агент полностью реинициализируется: cnew = rand(cmin, cmax). Вероятность реинициализации пропорциональна силе негативного сигнала: чем хуже регион, тем выше шанс полного перезапуска. Аналогия: район настолько плох, что нет смысла двигаться постепенно, вы садитесь в такси и едете в случайную точку города, надеясь на удачу.

Рисунок 1. Иллюстрация работы алгоритма dDCA
На иллюстрации отображено:
- Cell Structure — структура дендритной клетки с параметрами и визуализация детерминированного распределения lifespan,
- Signal Processing — расчёт сигналов Danger/Safe и контекста k по Danger Theory,
- Key Formulas — все ключевые формулы алгоритма,
- Algorithm Flow — пошаговая схема работы,
- Movement Strategies — три стратегии перемещения с формулами.
Переходим к написанию псевдокода алгоритма dDCA.
ИНИЦИАЛИЗАЦИЯ:
Для каждой клетки i = 1..N:
lifespan[i] = i × (maxLifespan / N) // равномерное распределение
k_accumulated[i] = 0
позиция[i] = случайная в пространстве поиска
ОСНОВНОЙ ЦИКЛ:
Для каждой клетки i:
// Сохранение предыдущего состояния
предыдущая_позиция[i] = позиция[i]
предыдущий_фитнес[i] = фитнес[i]
// Централизованный расчёт статистики
fMin = min(фитнес всех клеток)
fMax = max(фитнес всех клеток)
Для каждой клетки i:
// Нормализация и расчёт сигналов
f_norm = (фитнес[i] - fMin) / (fMax - fMin)
D = f_norm × 50
S = (1 - f_norm) × 50
k = D - safeWeight × S
// Обновление состояния клетки
lifespan[i] -= 50 // csm = 50 (константа)
k_accumulated[i] += k
iterations[i]++
Для каждой клетки i:
// Средний контекст за время жизни
k_mean = k_accumulated[i] / iterations[i]
// Генерация новой позиции
ЕСЛИ k_mean > 0:
LocalMutation(i) // Эксплуатация
ИНАЧЕ:
reinit_prob = min(|k_mean| / 50, 0.5)
ЕСЛИ random < reinit_prob:
GlobalReinit(i) // Глобальное исследование
ИНАЧЕ:
MoveTowardsBest(i) // Направленное исследование
// Проверка созревания
ЕСЛИ lifespan[i] ≤ 0:
Сброс клетки (lifespan, k_accumulated, iterations)
Контроль границ(i)
// Жадная селекция
Для каждой клетки i:
ЕСЛИ предыдущий_фитнес[i] > фитнес[i]:
Восстановить предыдущую позицию и фитнес
Обновить глобальное лучшее решение
Можем приступить к написанию кода алгоритма. Структура "Дендритная клетка" (S_dDCA_Cell) моделирует отдельную "дендритную клетку", представляющую собой элемент системы, обладающий специфическими свойствами и жизненным циклом.
Основные характеристики клетки:
- lifespan (время жизни) — текущее количество времени, которое клетка еще может существовать или функционировать. Этот показатель убывает со временем.
- k_accumulated (накопленный контекст) — значение, отражающее накопленную внутри клетки информацию или "контекст".
- initial_lifespan (начальное время жизни) — изначальное значение времени жизни клетки. Используется для сброса клетки в исходное состояние.
- iterations (счетчик итераций) — отслеживает, сколько раз клетка прошла через полный цикл обработки или "инкарнацию" с момента последнего сброса.
Методы (действия) клетки:
Init () Инициализация:
- Устанавливает начальные значения параметров клетки при ее создании.
- lifespan и initial_lifespan — устанавливаются равными переданному значению "ls" (начальное время жизни).
- k_accumulated — обнуляется (начинаем с чистого листа).
- iterations — обнуляется, так как это первая "инкарнация".
Reset () Сброс:
- Возвращает клетку в ее исходное состояние.
- lifespan — восстанавливается до значения "initial_lifespan".
- k_accumulated — сбрасывается на ноль.
- iterations — также сбрасывается на ноль, готовясь к новому циклу работы.
//———————————————————————————————————————————————————————————————————— // Структура дендритной клетки struct S_dDCA_Cell { double lifespan; // Текущее время жизни double k_accumulated; // Накопленный контекст double initial_lifespan; // Начальное время жизни (для сброса) int iterations; // Счётчик итераций в текущей инкарнации void Init (double ls) { lifespan = ls; initial_lifespan = ls; k_accumulated = 0.0; iterations = 0; } void Reset () { lifespan = initial_lifespan; k_accumulated = 0.0; iterations = 0; } }; //————————————————————————————————————————————————————————————————————
Класс "C_AO_dDCA" представляет собой реализацию детерминированного алгоритма дендритных клеток (dDCA) для решения задач поиска оптимальных решений. Он наследуется от базового класса "C_AO", который предоставляет общую структуру для оптимизационных алгоритмов.
Открытые (public) члены класса:
Конструктор C_AO_dDCA () —
- инициализирует основные атрибуты алгоритма,
- устанавливает параметры по умолчанию,
- создает массив "params" для хранения параметров с их именами и текущими значениями.
- метод для обновления внутренних параметров алгоритма на основе значений, хранящихся в массиве "params",
- после установки значений, проводит проверку (контроль границ) для обеспечения их корректности, устанавливая минимальные и максимальные допустимые значения.
- публичный метод для инициализации алгоритма — принимает интервалы поиска (rangeMinP, rangeMaxP, rangeStepP) и количество эпох (epochsP),
- вызывает стандартную процедуру инициализации (StandardInit) и, если она успешна, выполняет специфическую для dDCA инициализацию:
- создает массив "клеток" (cells) с размером, равным "popSize";
- инициализирует каждую клетку с помощью метода "Init", устанавливая их начальное время жизни (lifespan) равномерно распределенным в пределах от 0 до maxLifespan, что создает разнообразие в "возрасте" клеток, как описано в исходной статье авторов;
- инициализирует переменные для отслеживания минимального (fMin_pop) и максимального (fMax_pop) значения фитнес-функции в популяции.
Moving () Перемещение — публичный метод, отвечающий за основной цикл работы алгоритма, где клетки "движутся" или обновляются в пространстве поиска.
Revision () Ревизия — публичный метод, выполняющий корректирующие и оценочные действия по завершении этапа "Moving".
Открытые (public) члены данных:
- maxLifespan (максимальное время жизни) — максимальное значение времени жизни для клеток,
- safeWeight (вес "Safe" сигнала) — параметр, влияющий на расчет контекста клетки,
- mutationRate (скорость мутации) — параметр, определяющий силу и вероятность локальных мутаций.
Закрытые (private) члены класса:
- cells [] (массив клеток) — массив, содержащий объекты типа "S_dDCA_Cell", представляющие собой популяцию дендритных клеток,
- fMin_pop (минимальный фитнес в популяции) — хранит минимальное значение фитнес-функции, найденное среди всех клеток в текущей популяции,
- fMax_pop (максимальный фитнес в популяции) — хранит максимальное значение фитнес-функции, найденное среди всех клеток в текущей популяции.
Закрытые (private) методы:
- CalculateSignals () (расчет сигналов) — метод для вычисления различных сигналов (например, "Danger" (D), "Safe" (S), "ClonalSelectionMarker" (csm), "Context" (k)) на основе нормализованного фитнес-значения (f_norm);
- GenerateNewPosition () (генерация новой позиции) — метод для определения нового положения клетки в пространстве поиска, на основе среднего контекста популяции (k_mean);
- LocalMutation () (локальная мутация) — применяет небольшие случайные изменения к параметрам клетки (ее "позиции");
- MoveTowardsBest () (движение к лучшему) — перемещает клетку в направлении лучшей найденной на данный момент позиции;
- GlobalReinit () (глобальная реинициализация) — полностью перезапускает клетку;
- BoundaryControl () (контроль границ) — обеспечивает, чтобы параметры клетки оставались в пределах допустимых границ поиска;
- GetNormalizedFitness() (получение нормализованного фитнеса) — преобразует значение фитнес-функции к нормализованному диапазону, необходимо для корректного расчета сигналов.
//———————————————————————————————————————————————————————————————————— class C_AO_dDCA : public C_AO { public: ~C_AO_dDCA () { } C_AO_dDCA () { ao_name = "dDCA"; ao_desc = "Deterministic Dendritic Cell Algorithm"; ao_link = "https://www.mql5.com/ru/articles/20430"; popSize = 50; maxLifespan = 20.0; // Максимальный лимит времени жизни safeWeight = 2.0; // Вес Safe сигнала: k = D - safeWeight*S mutationRate = 0.01; // Сила локальной мутации ArrayResize (params, 4); params [0].name = "popSize"; params [0].val = popSize; params [1].name = "maxLifespan"; params [1].val = maxLifespan; params [2].name = "safeWeight"; params [2].val = safeWeight; params [3].name = "mutationRate"; params [3].val = mutationRate; } void SetParams () { popSize = (int)params [0].val; maxLifespan = params [1].val; safeWeight = params [2].val; mutationRate = params [3].val; if (popSize < 2) popSize = 2; if (maxLifespan < 1.0) maxLifespan = 1.0; if (safeWeight < 0.0) safeWeight = 0.0; if (mutationRate < 0.0) mutationRate = 0.0; if (mutationRate > 1.0) mutationRate = 1.0; } bool Init (const double &rangeMinP [], const double &rangeMaxP [], const double &rangeStepP [], const int epochsP); void Moving (); void Revision (); //------------------------------------------------------------------ double maxLifespan; double safeWeight; double mutationRate; private: //--------------------------------------------------------- S_dDCA_Cell cells []; double fMin_pop; // Минимальный фитнес в популяции double fMax_pop; // Максимальный фитнес в популяции void CalculateSignals (double f_norm, double &D, double &S, double &csm, double &k); void GenerateNewPosition (int idx, double k_mean); void LocalMutation (int idx); void MoveTowardsBest (int idx); void GlobalReinit (int idx); void BoundaryControl (int idx); double GetNormalizedFitness (double f); }; //————————————————————————————————————————————————————————————————————
Метод "Init" класса "C_AO_dDCA" отвечает за первоначальную настройку и подготовку алгоритма к работе. Он получает информацию о диапазоне поиска параметров, шагах поиска и количестве обучающих эпох. Первым шагом вызывается метод "StandardInit", который выполняет общую инициализацию, необходимую для всех оптимизационных алгоритмов.
Размер массива "cells" хранит все "дендритные клетки", устанавливается равным "popSize" — значению, определяющему количество клеток в популяции. Рассчитывается "lifespanIncrement" — величина, на которую будет увеличиваться время жизни каждой последующей клетки. Это делается путем деления максимального времени жизни (maxLifespan) на общее количество клеток (popSize).
В цикле для каждой клетки происходит следующее: вычисляется начальное время жизни для текущей клетки, каждая клетка получает свое уникальное начальное время жизни, равномерно распределенное в интервале от "lifespanIncrement" до "maxLifespan", вызывается метод "Init" для текущей клетки, передавая ей рассчитанное значение "ls". Это настраивает клетку с ее индивидуальным временем жизни, обнуляет накопленный контекст и счетчик итераций.
Такое дробление времени жизни на разные интервалы позволяет клеткам иметь различные "окна наблюдения" или "периоды активности" в процессе работы алгоритма, что соответствует одной из ключевых идей оригинальной статьи по dDCA.
В конце метода возвращается "true", инициализация алгоритма прошла успешно.//———————————————————————————————————————————————————————————————————— bool C_AO_dDCA::Init (const double &rangeMinP [], const double &rangeMaxP [], const double &rangeStepP [], const int epochsP) { if (!StandardInit (rangeMinP, rangeMaxP, rangeStepP)) return false; //------------------------------------------------------------------ // Инициализация клеток с равномерным распределением lifespan // Это обеспечивает разные "временные окна" как в статье авторов //------------------------------------------------------------------ ArrayResize (cells, popSize); double lifespanIncrement = maxLifespan / popSize; for (int i = 0; i < popSize; i++) { double ls = (i + 1) * lifespanIncrement; cells [i].Init (ls); } //------------------------------------------------------------------ return true; } //————————————————————————————————————————————————————————————————————
Метод "Moving" является основным рабочим циклом алгоритма dDCA. Он представляет собой последовательность шагов, моделирующих поведение дендритных клеток в процессе поиска решения.
Итерация 1. Случайная инициализация популяции.
- Если переменная "revision" имеет значение "false" (что указывает на первую итерацию), происходит случайное распределение начальных позиций всех клеток в пределах заданных диапазонов (rangeMin, rangeMax).
- Метод "u.RNDfromCI" генерирует случайное значение в указанном интервале.
- Метод "u.SeInDiSp" приводит сгенерированное значение к заданному шагу (rangeStep), обеспечивая дискретность поиска.
- После инициализации "revision" устанавливается в "true", и метод завершает выполнение, готовясь к основной обработке на следующей итерации.
Сохранение текущих координат и фитнес-значения. Этот шаг выполняется перед любыми дальнейшими расчетами.
- Для каждой клетки текущие координаты копируются в предыдущие координаты, текущий фитнес копируется в предыдущий фитнес.
- Важно: это критически важный шаг, так как он сохраняет состояние популяции на момент начала текущей итерации, которое будет использоваться для расчетов на этой итерации.
Обновление статистики популяции для нормализации:
- инициализируются переменные "fMin_pop" (минимальный фитнес) и fMax_pop (максимальный фитнес) с экстремальными значениями;
- итерируя по всем клеткам, происходит поиск истинных минимального и максимального значений фитнес-функции среди всех клеток, которые не имеют значения "-DBL_MAX" (фитнес еще не вычислен);
- защита от невалидных значений — если после обхода популяции "fMax_pop" остается "-DBL_MAX" или "fMin_pop" остается "DBL_MAX" (что может произойти, если все фитнес-значения некорректны или популяция не инициализирована), устанавливаются значения по умолчанию (1.0 и 0.0 соответственно), чтобы избежать ошибок при дальнейшей нормализации.
Обработка сигналов и обновление состояния клеток. Этот блок моделирует "чувствительность" и "распространение сигналов" в популяции дендритных клеток.
- Для каждой клетки вычисляется нормализованное значение фитнес-функции с использованием метода "GetNormalizedFitness", вызывается метод "CalculateSignals" для определения сигналов "Danger" (D), "Safe" (S), "Clonal Selection Marker" (csm) и "Context" (k). Эти сигналы отражают "опасность" текущего окружения (D), "безопасность" (S), маркер для клонального отбора (csm) и "контекст" (k) – внутреннее состояние клетки. Далее:
- Обновление состояния клетки:
- cells[i].lifespan -= csm: Уменьшается время жизни клетки пропорционально маркеру клонального отбора.
- cells[i].k_accumulated += k: Накапливается значение сигнала "Context" (k) в k_accumulated клетки.
- cells[i].iterations++: Увеличивается счетчик итераций клетки.
- Обновление состояния клетки:
Генерация новых позиций. На этом этапе происходит принятие решений о дальнейшем поведении каждой клетки.
Для каждой клетки:
- расчет среднего контекста — вычисляется среднее значение накопленного контекста "k_mean" клетки за все ее итерации;
- если клетка "созрела", принимается решение на основе ее накопленного контекста;
- если клетка не созрела, исследование продолжается с текущей стратегией, которая также зависит от накопленного контекста;
- в обоих случаях (созревшая или нет) вызывается метод "GenerateNewPosition";
- после определения новой позиции, метод "BoundaryControl" гарантирует, что координаты клетки останутся в пределах допустимых границ поиска (rangeMin, rangeMax).
В целом, метод "Moving" моделирует:
- первую фазу — случайное распределение начальных точек,
- сохранение состояния — фиксация лучших достижений перед началом изменений,
- оценку популяции — определение текущего диапазона качества решений,
- обработку сигналов — каждая клетка "чувствует" окружение (представленное ее фитнес-значением) и генерирует внутренние сигналы (D, S, csm, k),
- управление временем жизни — время жизни клетки регулируется сигналом "csm",
- накопление контекста — информация о "здоровье" и "опасности" окружения накапливается в "k_accumulated",
- принятие решения — зрелые клетки принимают более радикальные решения, в то время как молодые клетки продолжают исследование,
- использование стратегии — новая позиция генерируется на основе накопленного контекста (k_mean), что позволяет клеткам адаптироваться к локальной или глобальной обстановке.
//———————————————————————————————————————————————————————————————————— void C_AO_dDCA::Moving () { //------------------------------------------------------------------ // Итерация 1: случайная инициализация популяции //------------------------------------------------------------------ if (!revision) { for (int i = 0; i < popSize; i++) { for (int c = 0; c < coords; c++) { a [i].c [c] = u.RNDfromCI (rangeMin [c], rangeMax [c]); a [i].c [c] = u.SeInDiSp (a [i].c [c], rangeMin [c], rangeMax [c], rangeStep [c]); } } revision = true; return; } //------------------------------------------------------------------ // ШАГ 1: Сохраняем текущие координаты и фитнес // ВАЖНО: это нужно сделать первым, до любых расчётов! // a[i].f содержит фитнес, вычисленный после предыдущего Moving() //------------------------------------------------------------------ for (int i = 0; i < popSize; i++) { ArrayCopy (a [i].cP, a [i].c, 0, 0, coords); a [i].fP = a [i].f; } //------------------------------------------------------------------ // ШАГ 2: Обновляем статистику популяции для нормализации // Используем fP (только что сохранённый актуальный фитнес) //------------------------------------------------------------------ fMin_pop = DBL_MAX; fMax_pop = -DBL_MAX; for (int i = 0; i < popSize; i++) { if (a [i].fP != -DBL_MAX) // Проверка на инициализацию { if (a [i].fP > fMax_pop) fMax_pop = a [i].fP; if (a [i].fP < fMin_pop) fMin_pop = a [i].fP; } } // Защита от невалидных значений if (fMax_pop == -DBL_MAX || fMin_pop == DBL_MAX) { fMax_pop = 1.0; fMin_pop = 0.0; } //------------------------------------------------------------------ // ШАГ 3: Обработка сигналов и обновление состояния клеток // Централизованная обработка как в оригинальном dDCA //------------------------------------------------------------------ for (int i = 0; i < popSize; i++) { // Нормализация фитнеса double f_norm = GetNormalizedFitness (a [i].fP); // Расчёт сигналов double D, S, csm, k; CalculateSignals (f_norm, D, S, csm, k); // Обновление состояния клетки cells [i].lifespan -= csm; cells [i].k_accumulated += k; cells [i].iterations++; } //------------------------------------------------------------------ // ШАГ 4: Генерация новых позиций //------------------------------------------------------------------ for (int i = 0; i < popSize; i++) { // Средний контекст за время жизни double k_mean = cells [i].k_accumulated / MathMax (cells [i].iterations, 1); // Проверка на созревание if (cells [i].lifespan <= 0.0) { // Клетка созрела - принимаем решение на основе накопленного контекста GenerateNewPosition (i, k_mean); cells [i].Reset (); } else { // Клетка не созрела - продолжаем исследование с текущей стратегией // Стратегия зависит от накопленного контекста GenerateNewPosition (i, k_mean); } BoundaryControl (i); } } //————————————————————————————————————————————————————————————————————
Метод "GetNormalizedFitness" отвечает за масштабирование (нормализацию) значения фитнес-функции в стандартный диапазон от 0 до 1. Это важно для того, чтобы различные фитнес-функции или фитнес-значения, полученные в разных состояниях поиска, могли быть корректно сравнены и использованы в дальнейших расчетах.
//———————————————————————————————————————————————————————————————————— // Нормализация фитнеса в диапазон [0, 1] //———————————————————————————————————————————————————————————————————— double C_AO_dDCA::GetNormalizedFitness (double f) { if (f == -DBL_MAX) return 0.5; double range = fMax_pop - fMin_pop; if (range < 1e-10) return 0.5; double norm = (f - fMin_pop) / range; // Ограничение в [0, 1] if (norm < 0.0) norm = 0.0; if (norm > 1.0) norm = 1.0; return norm; } //————————————————————————————————————————————————————————————————————
Метод "CalculateSignals" берёт показатель "приспособленности" какого-либо элемента, который уже был приведен к универсальному масштабу. На основе этого показателя он рассчитывает четыре новых характеристики, которые отражают:
- (S) — показывает, насколько этот элемент является "перспективным" или "привлекательным",
- (D) — показывает, насколько элемент является "неперспективным" или "менее привлекательным".
"Совместную стимуляцию" (csm). Это общее значение, которое учитывает как "опасность", так и "безопасность" вместе. В конкретной реализации оно всегда будет равно 50, если исходный показатель приемлемости был приведен к диапазону от 0 до 50.
"Контекст" (k). Это более сложное значение, которое учитывает "опасность", но с учетом того, насколько "безопасность" может её подавлять. Оно помогает оценить, насколько действительно стоит полагаться на "опасный" сигнал, учитывая наличие "безопасных" факторов.
Таким образом, метод преобразует один входной показатель качества в несколько новых, которые более детально описывают его "привлекательность" и "отталкивающие" свойства, учитывая разные аспекты для принятия решений.
//———————————————————————————————————————————————————————————————————— // Расчёт сигналов D и S // // Формулы из статьи (с нормализацией в [0, 50] как в эксперименте): // csm = S + D (1) - costimulation // k = D - 2*S (4) - context (или D - safeWeight*S) // // Интерпретация для оптимизации: // D = низкий фитнес = нужно уходить // S = высокий фитнес = перспективный регион //———————————————————————————————————————————————————————————————————— void C_AO_dDCA::CalculateSignals (double f_norm, double &D, double &S, double &csm, double &k) { // Нормализация в диапазон [0, 50] как в статье D = f_norm * 50.0; S = (1.0 - f_norm) * 50.0; // Формула (1): csm = S + D = 50 (константа при данной нормализации) csm = S + D; // Формула (4): k = D - safeWeight * S k = D - safeWeight * S; } //————————————————————————————————————————————————————————————————————
Метод "GenerateNewPosition" определяет, каким образом будет генерироваться новая позиция (или решение) для определенного агента в алгоритме, основываясь на "контексте" текущей ситуации. Контекст этот описывается средней величиной "k_mean".
Если "k_mean" положительный — это означает, что текущая область поиска считается "хорошей" или "перспективной". В этом случае метод выбирает стратегию эксплуатации, то есть локальной мутации. Агент остается вблизи своего текущего положения и вносит небольшие, точечные изменения, как бы "дорабатывая" или "исследуя" мельчайшие детали в этой хорошей области.
Если "k_mean" неположительный — это указывает на то, что текущая область поиска считается "плохой" или "менее перспективной". Здесь алгоритм переходит к стратегии исследования, призванной выбраться из этой зоны:
Вероятность переинициализации. Метод сначала генерирует случайное число. Это число сравнивается с вероятностью переинициализации (reinit_prob). Эта вероятность тем выше, чем более отрицательным является "k_mean" (чем хуже контекст) и ограничена сверху (например, 0.5, то есть не более 50% случаев).
Если случайное число меньше вероятности переинициализации. Выполняется глобальная переинициализация. Это означает, что агент полностью "сбрасывается" и помещается в совершенно новую, случайную позицию в пространстве поиска. Это как начать все сначала в другой части поиска.
В противном случае(если случайное число больше вероятности переинициализации). Выполняется движение к лучшему решению. Это означает, что агент пытается направиться к уже найденному наилучшему решению, надеясь, что это приведет его к лучшему участку пространства поиска, минуя текущую плохую область.Таким образом, метод "GenerateNewPosition" действует как "умный" способ генерации новых решений:
- вознаграждает "хорошие" области, позволяя агентам детально их исследовать;
- выводит агентов из "плохих" областей, либо давая им шанс на "счастливую случайность" (глобальная переинициализация), либо направляя их к уже найденному успеху (движение к лучшему).
//———————————————————————————————————————————————————————————————————— // Генерация новой позиции на основе контекста // // k > 0: хороший регион (аналог "mature" в dDCA) // ? локальная мутация (эксплуатация) // // k <= 0: плохой регион (аналог "semi-mature" в dDCA) // ? движение к лучшему или переинициализация (исследование) //———————————————————————————————————————————————————————————————————— void C_AO_dDCA::GenerateNewPosition (int idx, double k_mean) { if (k_mean > 0.0) { // Положительный контекст - хороший регион // Локальное исследование вокруг текущей позиции LocalMutation (idx); } else { // Отрицательный контекст - плохой регион // Нужно уходить: либо к лучшему, либо случайно double r = u.RNDfromCI (0.0, 1.0); // Чем хуже контекст (более отрицательный k), тем выше шанс переинициализации double reinit_prob = MathMin (MathAbs (k_mean) / 50.0, 0.5); if (r < reinit_prob) { // Глобальная переинициализация GlobalReinit (idx); } else { // Движение к лучшему решению MoveTowardsBest (idx); } } } //————————————————————————————————————————————————————————————————————
Метод "LocalMutation" вносит небольшие, случайные изменения в каждую координату текущей позиции элемента. Эти изменения происходят в пределах установленных границ рабочей области для каждой координаты и зависят от общей "скорости мутации", что позволяет исследовать "соседние" решения относительно текущего.
//———————————————————————————————————————————————————————————————————— // Локальная мутация - исследование окрестности текущей позиции //———————————————————————————————————————————————————————————————————— void C_AO_dDCA::LocalMutation (int idx) { for (int c = 0; c < coords; c++) { double range = rangeMax [c] - rangeMin [c]; double mutation = mutationRate * range * u.RNDfromCI (-1.0, 1.0); a [idx].c [c] = a [idx].cP [c] + mutation; } } //————————————————————————————————————————————————————————————————————
Метод "MoveTowardsBest" описывает стратегию, при которой агент пытается приблизиться к наилучшему известному решению, добавляя при этом некоторый случайный "шум" для поддержания исследовательских свойств. Метод балансирует между эксплуатацией (стремление к лучшему найденному решению) и исследованием (внезапные, небольшие случайные отклонения вокруг движущейся траектории). Это позволяет элементу эффективно перемещаться в направлении перспективных областей, но при этом не "застревать" слишком сильно в одной точке и сохранять способность находить новые, возможно, даже лучшие решения.
//———————————————————————————————————————————————————————————————————— // Движение к лучшему известному решению с шумом //———————————————————————————————————————————————————————————————————— void C_AO_dDCA::MoveTowardsBest (int idx) { // Проверка: если cB ещё не инициализирован, делаем локальную мутацию if (fB == -DBL_MAX) { LocalMutation (idx); return; } for (int c = 0; c < coords; c++) { double r = u.RNDfromCI (0.0, 1.0); double range = rangeMax [c] - rangeMin [c]; // Движение к лучшему + случайный шум a [idx].c [c] = a [idx].cP [c] + r * (cB [c] - a [idx].cP [c]) + mutationRate * range * u.RNDfromCI (-1.0, 1.0); } } //————————————————————————————————————————————————————————————————————
Метод "GlobalReinit" помещает элемент в абсолютно новую, случайно выбранную точку в пространства поиска. Это действует как "полный сброс" или "прыжок" в совершенно другую часть пространства решений. Такой подход может быть полезен, если текущий алгоритм застрял в локальном оптимуме и нужно "вытолкнуть" его оттуда, чтобы начать исследование с чистого листа.
//———————————————————————————————————————————————————————————————————— // Глобальная переинициализация - полностью случайная позиция //———————————————————————————————————————————————————————————————————— void C_AO_dDCA::GlobalReinit (int idx) { for (int c = 0; c < coords; c++) { a [idx].c [c] = u.RNDfromCI (rangeMin [c], rangeMax [c]); } } //————————————————————————————————————————————————————————————————————
Метод предназначен для удержания элемента (агента, частицы) в пределах заданных допустимых границ для его координат. Если элемент оказывается за пределами этих границ, метод пытается вернуть его обратно, используя различные стратегии.
Метод BoundaryControl является корректирующим механизмом. Он гарантирует, что элементы не выходят за пределы определяемого пространства поиска. Стратегия "отражения" позволяет элементу "оттолкнуться" от границы и вернуться в допустимую область, сохраняя при этом некоторую информацию о своем движении. Дополнительная рандомизация при пересечении границы помогает избежать застреваний. И наконец, последняя строка гарантирует, что позиция соответствует дискретным правилам пространства.
//———————————————————————————————————————————————————————————————————— // Контроль границ с отражением //———————————————————————————————————————————————————————————————————— void C_AO_dDCA::BoundaryControl (int idx) { for (int c = 0; c < coords; c++) { if (a [idx].c [c] < rangeMin [c]) { a [idx].c [c] = rangeMin [c] + MathAbs (a [idx].c [c] - rangeMin [c]); if (a [idx].c [c] > rangeMax [c]) { a [idx].c [c] = u.RNDfromCI (rangeMin [c], rangeMax [c]); } } if (a [idx].c [c] > rangeMax [c]) { a [idx].c [c] = rangeMax [c] - MathAbs (a [idx].c [c] - rangeMax [c]); if (a [idx].c [c] < rangeMin [c]) { a [idx].c [c] = u.RNDfromCI (rangeMin [c], rangeMax [c]); } } a [idx].c [c] = u.SeInDiSp (a [idx].c [c], rangeMin [c], rangeMax [c], rangeStep [c]); } } //————————————————————————————————————————————————————————————————————
Метод "Revision" выполняет две ключевые функции:
- селекция (отбор) — он определяет, стоит ли сохранять новую (потенциально улучшенную) позицию агента или вернуться к предыдущей лучшей,
- обновление глобальных лучшего — он отслеживает наилучшую и наихудшую найденные позиции среди всех агентов и сохраняет эту информацию.
Селекция: жадный выбор. Суть селекции. Этот блок реализует "жадную" стратегию. Если новое положение агента оказалось хуже, чем его собственное лучшее известное положение, агент "никогда не забудет" свое предыдущее лучшее положение и вернется к нему.
Метод "Revision" используется для стабилизации и отслеживания прогресса популяции. Он обеспечивает, что каждый агент не теряет свои лучшие найденные решения (благодаря жадной селекции) и помогает определить общее лучшее найденное решение во всей популяции. Алгоритм основан на задачах максимизации, то "fB" и "cB" будут хранить наилучшие результаты.
//———————————————————————————————————————————————————————————————————— void C_AO_dDCA::Revision () { //------------------------------------------------------------------ // Селекция: жадный выбор - сохраняем позицию если она лучше //------------------------------------------------------------------ for (int i = 0; i < popSize; i++) { // Если предыдущий фитнес лучше текущего - возвращаемся if (a [i].fP > a [i].f && a [i].fP != -DBL_MAX) { a [i].f = a [i].fP; ArrayCopy (a [i].c, a [i].cP, 0, 0, coords); } } //------------------------------------------------------------------ // Обновление глобального лучшего //------------------------------------------------------------------ for (int i = 0; i < popSize; i++) { if (a [i].f > fB) { fB = a [i].f; ArrayCopy (cB, a [i].c, 0, 0, coords); } } } //————————————————————————————————————————————————————————————————————
Результаты тестов
Теперь можем познакомиться с результатами тестирования алгоритма на наших тестовых функциях, алгоритм набирает 41%, слабее всего чувствует себя на дискретных функциях.
dDCA|Deterministic Dendritic Cell Algorithm|50.0|20.0|2.0|0.01|
=============================
5 Hilly's; Func runs: 10000; result: 0.8798800651743539
25 Hilly's; Func runs: 10000; result: 0.4788852312258377
500 Hilly's; Func runs: 10000; result: 0.27717376068435823
=============================
5 Forest's; Func runs: 10000; result: 0.6340906667281795
25 Forest's; Func runs: 10000; result: 0.3689169839474446
500 Forest's; Func runs: 10000; result: 0.21510602459276465
=============================
5 Megacity's; Func runs: 10000; result: 0.5292307692307692
25 Megacity's; Func runs: 10000; result: 0.2163076923076923
500 Megacity's; Func runs: 10000; result: 0.10510769230769328
=============================
All score: 3.70470 (41.16%)
На визуализации заметен разброс результатов на функциях малой размерности и на дискретной функции "Megacity" низкие показатели сходимости. Популяция разбивается на группы клеток агентов, исследуя перспективные области, но этого не достаточно с точки зрения общего поиска ко всему пространству решений.

dDCA на тестовой функции Hilly

dDCA на тестовой функции Forest

dDCA на тестовой функции Megacity
Для общего ознакомления с работой алгоритма dDCA, посмотрим его поведение на стандартных тестовых функциях, которые не участвуют в нашем тестировании, но имеют свои поставленные задачи. Разброс значений менее заметен.

dDCA на стандартной тестовой функции Ackley

dDCA на стандартной тестовой функции Shaffer

dDCA на стандартной тестовой функции Paraboloid
Алгоритм dDCA представлен в нашей рейтинговой таблице лучших популяционных методов оптимизации ознакомительно.
| № | AO | Description | Hilly | Hilly Final | Forest | Forest Final | Megacity (discrete) | Megacity Final | Final Result | % of MAX | ||||||
| 10 p (5 F) | 50 p (25 F) | 1000 p (500 F) | 10 p (5 F) | 50 p (25 F) | 1000 p (500 F) | 10 p (5 F) | 50 p (25 F) | 1000 p (500 F) | ||||||||
| 1 | DOAdingom | dingo_optimization_algorithm_M | 0,47968 | 0,45367 | 0,46369 | 1,39704 | 0,94145 | 0,87909 | 0,91454 | 2,73508 | 0,78615 | 0,86061 | 0,84805 | 2,49481 | 6,627 | 73,63 |
| 2 | ANS | across neighbourhood search | 0,94948 | 0,84776 | 0,43857 | 2,23581 | 1,00000 | 0,92334 | 0,39988 | 2,32323 | 0,70923 | 0,63477 | 0,23091 | 1,57491 | 6,134 | 68,15 |
| 3 | CLA | code lock algorithm (joo) | 0,95345 | 0,87107 | 0,37590 | 2,20042 | 0,98942 | 0,91709 | 0,31642 | 2,22294 | 0,79692 | 0,69385 | 0,19303 | 1,68380 | 6,107 | 67,86 |
| 4 | AMOm | animal migration ptimization M | 0,90358 | 0,84317 | 0,46284 | 2,20959 | 0,99001 | 0,92436 | 0,46598 | 2,38034 | 0,56769 | 0,59132 | 0,23773 | 1,39675 | 5,987 | 66,52 |
| 5 | (P+O)ES | (P+O) evolution strategies | 0,92256 | 0,88101 | 0,40021 | 2,20379 | 0,97750 | 0,87490 | 0,31945 | 2,17185 | 0,67385 | 0,62985 | 0,18634 | 1,49003 | 5,866 | 65,17 |
| 6 | CTA | comet tail algorithm (joo) | 0,95346 | 0,86319 | 0,27770 | 2,09435 | 0,99794 | 0,85740 | 0,33949 | 2,19484 | 0,88769 | 0,56431 | 0,10512 | 1,55712 | 5,846 | 64,96 |
| 7 | TETA | time evolution travel algorithm (joo) | 0,91362 | 0,82349 | 0,31990 | 2,05701 | 0,97096 | 0,89532 | 0,29324 | 2,15952 | 0,73462 | 0,68569 | 0,16021 | 1,58052 | 5,797 | 64,41 |
| 8 | SDSm | stochastic diffusion search M | 0,93066 | 0,85445 | 0,39476 | 2,17988 | 0,99983 | 0,89244 | 0,19619 | 2,08846 | 0,72333 | 0,61100 | 0,10670 | 1,44103 | 5,709 | 63,44 |
| 9 | BOAm | billiards optimization algorithm M | 0,95757 | 0,82599 | 0,25235 | 2,03590 | 1,00000 | 0,90036 | 0,30502 | 2,20538 | 0,73538 | 0,52523 | 0,09563 | 1,35625 | 5,598 | 62,19 |
| 10 | AAm | archery algorithm M | 0,91744 | 0,70876 | 0,42160 | 2,04780 | 0,92527 | 0,75802 | 0,35328 | 2,03657 | 0,67385 | 0,55200 | 0,23738 | 1,46323 | 5,548 | 61,64 |
| 11 | ESG | evolution of social groups (joo) | 0,99906 | 0,79654 | 0,35056 | 2,14616 | 1,00000 | 0,82863 | 0,13102 | 1,95965 | 0,82333 | 0,55300 | 0,04725 | 1,42358 | 5,529 | 61,44 |
| 12 | SIA | simulated isotropic annealing (joo) | 0,95784 | 0,84264 | 0,41465 | 2,21513 | 0,98239 | 0,79586 | 0,20507 | 1,98332 | 0,68667 | 0,49300 | 0,09053 | 1,27020 | 5,469 | 60,76 |
| 13 | EOm | extremal_optimization_M | 0,76166 | 0,77242 | 0,31747 | 1,85155 | 0,99999 | 0,76751 | 0,23527 | 2,00277 | 0,74769 | 0,53969 | 0,14249 | 1,42987 | 5,284 | 58,71 |
| 14 | BBO | biogeography based optimization | 0,94912 | 0,69456 | 0,35031 | 1,99399 | 0,93820 | 0,67365 | 0,25682 | 1,86867 | 0,74615 | 0,48277 | 0,17369 | 1,40261 | 5,265 | 58,50 |
| 15 | ACS | artificial cooperative search | 0,75547 | 0,74744 | 0,30407 | 1,80698 | 1,00000 | 0,88861 | 0,22413 | 2,11274 | 0,69077 | 0,48185 | 0,13322 | 1,30583 | 5,226 | 58,06 |
| 16 | DA | dialectical algorithm | 0,86183 | 0,70033 | 0,33724 | 1,89940 | 0,98163 | 0,72772 | 0,28718 | 1,99653 | 0,70308 | 0,45292 | 0,16367 | 1,31967 | 5,216 | 57,95 |
| 17 | BHAm | black hole algorithm M | 0,75236 | 0,76675 | 0,34583 | 1,86493 | 0,93593 | 0,80152 | 0,27177 | 2,00923 | 0,65077 | 0,51646 | 0,15472 | 1,32195 | 5,196 | 57,73 |
| 18 | ASO | anarchy society optimization | 0,84872 | 0,74646 | 0,31465 | 1,90983 | 0,96148 | 0,79150 | 0,23803 | 1,99101 | 0,57077 | 0,54062 | 0,16614 | 1,27752 | 5,178 | 57,54 |
| 19 | RFO | royal flush optimization (joo) | 0,83361 | 0,73742 | 0,34629 | 1,91733 | 0,89424 | 0,73824 | 0,24098 | 1,87346 | 0,63154 | 0,50292 | 0,16421 | 1,29867 | 5,089 | 56,55 |
| 20 | AOSm | atomic orbital search M | 0,80232 | 0,70449 | 0,31021 | 1,81702 | 0,85660 | 0,69451 | 0,21996 | 1,77107 | 0,74615 | 0,52862 | 0,14358 | 1,41835 | 5,006 | 55,63 |
| 21 | TSEA | turtle shell evolution algorithm (joo) | 0,96798 | 0,64480 | 0,29672 | 1,90949 | 0,99449 | 0,61981 | 0,22708 | 1,84139 | 0,69077 | 0,42646 | 0,13598 | 1,25322 | 5,004 | 55,60 |
| 22 | BSA | backtracking_search_algorithm | 0,97309 | 0,54534 | 0,29098 | 1,80941 | 0,99999 | 0,58543 | 0,21747 | 1,80289 | 0,84769 | 0,36953 | 0,12978 | 1,34700 | 4,959 | 55,10 |
| 23 | DE | differential evolution | 0,95044 | 0,61674 | 0,30308 | 1,87026 | 0,95317 | 0,78896 | 0,16652 | 1,90865 | 0,78667 | 0,36033 | 0,02953 | 1,17653 | 4,955 | 55,06 |
| 24 | SRA | successful restaurateur algorithm (joo) | 0,96883 | 0,63455 | 0,29217 | 1,89555 | 0,94637 | 0,55506 | 0,19124 | 1,69267 | 0,74923 | 0,44031 | 0,12526 | 1,31480 | 4,903 | 54,48 |
| 25 | BO | bonobo_optimizer | 0,77565 | 0,63805 | 0,32908 | 1,74278 | 0,88088 | 0,76344 | 0,25573 | 1,90005 | 0,61077 | 0,49846 | 0,14246 | 1,25169 | 4,895 | 54,38 |
| 26 | CRO | chemical reaction optimisation | 0,94629 | 0,66112 | 0,29853 | 1,90593 | 0,87906 | 0,58422 | 0,21146 | 1,67473 | 0,75846 | 0,42646 | 0,12686 | 1,31178 | 4,892 | 54,36 |
| 27 | BIO | blood inheritance optimization (joo) | 0,81568 | 0,65336 | 0,30877 | 1,77781 | 0,89937 | 0,65319 | 0,21760 | 1,77016 | 0,67846 | 0,47631 | 0,13902 | 1,29378 | 4,842 | 53,80 |
| 28 | DOA | dream_optimization_algorithm | 0,85556 | 0,70085 | 0,37280 | 1,92921 | 0,73421 | 0,48905 | 0,24147 | 1,46473 | 0,77231 | 0,47354 | 0,18561 | 1,43146 | 4,825 | 53,62 |
| 29 | BSA | bird swarm algorithm | 0,89306 | 0,64900 | 0,26250 | 1,80455 | 0,92420 | 0,71121 | 0,24939 | 1,88479 | 0,69385 | 0,32615 | 0,10012 | 1,12012 | 4,809 | 53,44 |
| 30 | DEA | dolphin_echolocation_algorithm | 0,75995 | 0,67572 | 0,34171 | 1,77738 | 0,89582 | 0,64223 | 0,23941 | 1,77746 | 0,61538 | 0,44031 | 0,15115 | 1,20684 | 4,762 | 52,91 |
| 31 | HS | harmony search | 0,86509 | 0,68782 | 0,32527 | 1,87818 | 0,99999 | 0,68002 | 0,09590 | 1,77592 | 0,62000 | 0,42267 | 0,05458 | 1,09725 | 4,751 | 52,79 |
| 32 | SSG | saplings sowing and growing | 0,77839 | 0,64925 | 0,39543 | 1,82308 | 0,85973 | 0,62467 | 0,17429 | 1,65869 | 0,64667 | 0,44133 | 0,10598 | 1,19398 | 4,676 | 51,95 |
| 33 | BCOm | bacterial chemotaxis optimization M | 0,75953 | 0,62268 | 0,31483 | 1,69704 | 0,89378 | 0,61339 | 0,22542 | 1,73259 | 0,65385 | 0,42092 | 0,14435 | 1,21912 | 4,649 | 51,65 |
| 34 | ABO | african buffalo optimization | 0,83337 | 0,62247 | 0,29964 | 1,75548 | 0,92170 | 0,58618 | 0,19723 | 1,70511 | 0,61000 | 0,43154 | 0,13225 | 1,17378 | 4,634 | 51,49 |
| 35 | (PO)ES | (PO) evolution strategies | 0,79025 | 0,62647 | 0,42935 | 1,84606 | 0,87616 | 0,60943 | 0,19591 | 1,68151 | 0,59000 | 0,37933 | 0,11322 | 1,08255 | 4,610 | 51,22 |
| 36 | FBA | fractal-based Algorithm | 0,79000 | 0,65134 | 0,28965 | 1,73099 | 0,87158 | 0,56823 | 0,18877 | 1,62858 | 0,61077 | 0,46062 | 0,12398 | 1,19537 | 4,555 | 50,61 |
| 37 | TSm | tabu search M | 0,87795 | 0,61431 | 0,29104 | 1,78330 | 0,92885 | 0,51844 | 0,19054 | 1,63783 | 0,61077 | 0,38215 | 0,12157 | 1,11449 | 4,536 | 50,40 |
| 38 | BSO | brain storm optimization | 0,93736 | 0,57616 | 0,29688 | 1,81041 | 0,93131 | 0,55866 | 0,23537 | 1,72534 | 0,55231 | 0,29077 | 0,11914 | 0,96222 | 4,498 | 49,98 |
| 39 | WOAm | wale optimization algorithm M | 0,84521 | 0,56298 | 0,26263 | 1,67081 | 0,93100 | 0,52278 | 0,16365 | 1,61743 | 0,66308 | 0,41138 | 0,11357 | 1,18803 | 4,476 | 49,74 |
| 40 | AEFA | artificial electric field algorithm | 0,87700 | 0,61753 | 0,25235 | 1,74688 | 0,92729 | 0,72698 | 0,18064 | 1,83490 | 0,66615 | 0,11631 | 0,09508 | 0,87754 | 4,459 | 49,55 |
| 41 | AEO | artificial ecosystem-based optimization algorithm | 0,91380 | 0,46713 | 0,26470 | 1,64563 | 0,90223 | 0,43705 | 0,21400 | 1,55327 | 0,66154 | 0,30800 | 0,28563 | 1,25517 | 4,454 | 49,49 |
| 42 | CAm | camel algorithm M | 0,78684 | 0,56042 | 0,35133 | 1,69859 | 0,82772 | 0,56041 | 0,24336 | 1,63149 | 0,64846 | 0,33092 | 0,13418 | 1,11356 | 4,444 | 49,37 |
| 43 | ACOm | ant colony optimization M | 0,88190 | 0,66127 | 0,30377 | 1,84693 | 0,85873 | 0,58680 | 0,15051 | 1,59604 | 0,59667 | 0,37333 | 0,02472 | 0,99472 | 4,438 | 49,31 |
| 44 | CMAES | covariance_matrix_adaptation_evolution_strategy | 0,76258 | 0,72089 | 0,00000 | 1,48347 | 0,82056 | 0,79616 | 0,00000 | 1,61672 | 0,75846 | 0,49077 | 0,00000 | 1,24923 | 4,349 | 48,33 |
| 45 | DA_duelist | duelist_algorithm | 0,92782 | 0,53778 | 0,27792 | 1,74352 | 0,86957 | 0,47536 | 0,18193 | 1,52686 | 0,62153 | 0,33569 | 0,11715 | 1,07437 | 4,345 | 48,28 |
| dDCA | deterministic_dendritic_cell_algorithm | 0,87988 | 0,47888 | 0,27717 | 1,63593 | 0,63409 | 0,36891 | 0,21510 | 1,21810 | 0,52923 | 0,21630 | 0,10510 | 0,85063 | 3,705 | 41,16 | |
| RW | random walk | 0,48754 | 0,32159 | 0,25781 | 1,06694 | 0,37554 | 0,21944 | 0,15877 | 0,75375 | 0,27969 | 0,14917 | 0,09847 | 0,52734 | 2,348 | 26,09 | |
Выводы
Предложенная адаптация детерминированного алгоритма дендритных клеток (dDCA) для задач непрерывной оптимизации продемонстрировала работоспособность подхода, однако не достигла уровня лучших популяционных методов. В ходе тестирования на стандартном наборе функций алгоритм набрал 41%, что ниже порогового значения 48% для включения в рейтинговую таблицу.
Анализ результатов выявил характерную особенность: алгоритм показывает наиболее слабые результаты на дискретных функциях. Это объясняется природой механизма сигналов — плавная нормализация фитнеса плохо отражает резкие переходы в дискретных ландшафтах, где соседние решения могут иметь кардинально различное качество.
Несмотря на общий результат, ряд компонентов алгоритма представляет самостоятельный интерес:
- детерминированное распределение времени жизни обеспечивает равномерную асинхронность популяции без введения дополнительной стохастичности;
- механизм накопления контекста позволяет принимать решения на основе статистики нескольких итераций, что повышает устойчивость к шуму фитнес-функции;
- адаптивный баланс исследования и эксплуатации на основе коллективного контекста популяции может служить альтернативой классическим схемам с явным параметром.
Данные компоненты могут быть использованы как составные элементы гибридных алгоритмов или адаптированы для специализированных задач, где важна устойчивость к зашумленным оценкам качества решений.

Рисунок 2. Цветовая градация алгоритмов по соответствующим тестам

Рисунок 3. Гистограмма результатов тестирования алгоритмов (по шкале от 0 до 100, чем больше, тем лучше, где 100 — максимально возможный теоретический результат, в архиве скрипт для расчета рейтинговой таблицы)
Плюсы и минусы алгоритма dDCA:
Плюсы:
- Быстрый.
Минусы:
- Более слабые результаты на дискретных функциях.
К статье прикреплён архив с актуальными версиями кодов алгоритмов. Автор статьи не несёт ответственности за абсолютную точность в описании канонических алгоритмов, во многие из них были внесены изменения для улучшения поисковых возможностей. Выводы и суждения, представленные в статьях, основываются на результатах проведённых экспериментов.
Программы, используемые в статье
| # | Имя | Тип | Описание |
|---|---|---|---|
| 1 | #C_AO.mqh | Включаемый файл | Родительский класс популяционных алгоритмов оптимизации |
| 2 | #C_AO_enum.mqh | Включаемый файл | Перечисление популяционных алгоритмов оптимизации |
| 3 | TestFunctions.mqh | Включаемый файл | Библиотека тестовых функций |
| 4 | TestStandFunctions.mqh | Включаемый файл | Библиотека функций тестового стенда |
| 5 | Utilities.mqh | Включаемый файл | Библиотека вспомогательных функций |
| 6 | CalculationTestResults.mqh | Включаемый файл | Скрипт для расчета результатов в сравнительную таблицу |
| 7 | Testing AOs.mq5 | Скрипт | Единый испытательный стенд для всех популяционных алгоритмов оптимизации |
| 8 | Simple use of population optimization algorithms.mq5 | Скрипт | Простой пример использования популяционных алгоритмов оптимизации без визуализации |
| 9 | Test_AO_dDCA.mq5 | Скрипт | Испытательный стенд для dDCA |
Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
Данная статья написана пользователем сайта и отражает его личную точку зрения. Компания MetaQuotes Ltd не несет ответственности за достоверность представленной информации, а также за возможные последствия использования описанных решений, стратегий или рекомендаций.
Знакомство с MQL5 (Часть 19): Автоматизация обнаружения волн Вульфа
Нейросети в трейдинге: Двусторонняя адаптивная временная корреляция (Основные компоненты)
Нейросети в трейдинге: Двусторонняя адаптивная временная корреляция (Окончание)
Знакомство с языком MQL5 (Часть 18): Введение в паттерн "Волны Вульфа"
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования