神经Boid优化算法2(NOA2)·进阶篇
(2/3)·传统群智能缺记忆、神经网络弱探索,NOA2 用个体神经网络改写 Boid 行为规则
「从记忆体里挑最优再回灌权重」
这段逻辑干了两件事:先在共享记忆数组里扫一遍,找出历史适应度最高的那条经验,再决定是否拿它去推权重。memory 被压成一维数组,每个个体占 coords_count+1 个槽,末位存适应度,所以取第 i 个个体的适应度要用 i*(coords_count+1)+coords_count 来偏移。 扫描从 i=1 开始,首条 best_fitness 直接取 memory[coords_count],也就是 0 号个体。若 fitness > best_fitness 就刷新 best_index,遍历完 memory_size 条后拿到全局最优记忆位。若 best_fitness <= best_local_fitness 直接 return,说明这次经验没超越本地最优,权重原样不动。 过了门槛才进权重更新:output_size 和 input_size 分别由 ArraySize(outputs) / ArraySize(inputs) 拿到,双层循环按 weight_index = o*input_size + i 写回 weights[weight_index] += learning_rate * outputs[o] * inputs[i],偏置 biases[o] 另加 learning_rate * outputs[o]。这是最朴素的梯度式增量,learning_rate 你调大一点收敛快但外汇贵金属回测里容易过冲,调小则稳但慢。 MemorizeExperience 负责把当前坐标 x[c] 和 fitness 写进环形缓冲 memory_index,写满 memory_size 后取模回卷;UpdateBestPosition 只在 current_fitness > fB 时把 x 整组拷进 cB。开 MT5 把 memory_size 设成 50 跑一遍 EURUSD 的 M15,能直接看到 fB 的爬升节奏。
class="type">class="kw">double best_fitness = memory [coords_count]; class=class="str">"cmt">// The first fitness function in memory for (class="type">int i = class="num">1; i < memory_size; i++) { class="type">class="kw">double fitness = memory [i * (coords_count + class="num">1) + coords_count]; if (fitness > best_fitness) { best_fitness = fitness; best_index = i; } } class=class="str">"cmt">// If the current experience is not better than the previous one, do not update the weights if (best_fitness <= best_local_fitness) class="kw">return; best_local_fitness = best_fitness; class=class="str">"cmt">// Simple method for updating weights class="type">int input_size = ArraySize(inputs); class="type">int output_size = ArraySize(outputs); class=class="str">"cmt">// Simple form of gradient update for (class="type">int o = class="num">0; o < output_size; o++) { for (class="type">int i = class="num">0; i < input_size; i++) { class="type">int weight_index = o * input_size + i; if (weight_index < ArraySize(weights)) { weights [weight_index] += learning_rate * outputs [o] * inputs [i]; } } class=class="str">"cmt">// Update offsets biases [o] += learning_rate * outputs [o]; } } class=class="str">"cmt">// Save current experience(coordinates and fitness) class="type">void MemorizeExperience(class="type">class="kw">double fitness, class="type">int coords_count) { class="type">int offset = memory_index * (coords_count + class="num">1); class=class="str">"cmt">// Save the coordinates for (class="type">int c = class="num">0; c < coords_count; c++) { memory [offset + c] = x [c]; } class=class="str">"cmt">// Save the fitness function memory [offset + coords_count] = fitness; class=class="str">"cmt">// Update the memory index memory_index = (memory_index + class="num">1) % memory_size; } class=class="str">"cmt">// Update the agent&class="macro">#x27;s best position class="type">void UpdateBestPosition(class="type">class="kw">double current_fitness, class="type">int coords_count) { if (current_fitness > fB) { fB = current_fitness; ArrayCopy(cB, x, class="num">0, class="num">0, WHOLE_ARRAY); } } }; class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class=class="str">"cmt">// Class of neuron-like optimization algorithm inherited from C_AO class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class C_AO_NOA2 : class="kw">public C_AO { class="kw">public: class=class="str">"cmt">//-------------------------------------------------------------------- ~C_AO_NOA2() { } C_AO_NOA2() { ao_name = "NOA2"; ao_desc = "Neuroboids Optimization Algorithm class="num">2 (joo)"; ao_link = "[MQL5官方文档]
◍ 群体智能算法的初始参数与回灌机制
这套基于群体行为的模型在初始化阶段定义了 12 个核心变量,种群规模 popSize 固定为 50,意味着每代并行演化的个体数量。凝聚权重 cohesionWeight 取 0.6,而分离权重 separationWeight 仅 0.005,说明个体更倾向向群体中心靠拢,而非彼此散开。 速度边界被压得很窄:maxSpeed=0.001、minSpeed=0.0001,配合 alignmentDist=0.1 的对齐感知半径,整体运动偏平滑、低噪声。神经部分 learningRate=0.01、neuralInfluence=0.3,表示网络输出对轨迹的干预占比三成,剩余七成由群体规则驱动。 代码里用 ArrayResize(params,12) 开辟参数槽,再把每个变量名和数值写回结构体,方便后续优化器直接读写。停滞计数器 m_stagnationCounter 归零、m_prevBestFitness 设为 -DBL_MAX,是为新一轮搜索清空历史最优锚点。 SetParams() 做反向操作:把 params[] 里的值灌回各全局变量。你在 MT5 里改完 params 数组再调 SetParams(),不用动算法主体就能换一套行为特征,外汇与贵金属市场波动剧烈,此类参数组合仅代表历史回测倾向,实盘需自担高风险。
popSize = class="num">50; class=class="str">"cmt">// population size cohesionWeight = class="num">0.6; class=class="str">"cmt">// cohesion weight cohesionDist = class="num">0.001; class=class="str">"cmt">// cohesion distance separationWeight = class="num">0.005; class=class="str">"cmt">// separation weight separationDist = class="num">0.03; class=class="str">"cmt">// separation distance alignmentWeight = class="num">0.1; class=class="str">"cmt">// alignment weight alignmentDist = class="num">0.1; class=class="str">"cmt">// alignment distance maxSpeed = class="num">0.001; class=class="str">"cmt">// maximum speed minSpeed = class="num">0.0001; class=class="str">"cmt">// minimum speed learningRate = class="num">0.01; class=class="str">"cmt">// neural network learning speed neuralInfluence = class="num">0.3; class=class="str">"cmt">// influence of the neural network on movement explorationRate = class="num">0.1; class=class="str">"cmt">// random exploration probability ArrayResize(params, class="num">12); params [class="num">0].name = "popSize"; params [class="num">0].val = popSize; params [class="num">1].name = "cohesionWeight"; params [class="num">1].val = cohesionWeight; params [class="num">2].name = "cohesionDist"; params [class="num">2].val = cohesionDist; params [class="num">3].name = "separationWeight"; params [class="num">3].val = separationWeight; params [class="num">4].name = "separationDist"; params [class="num">4].val = separationDist; params [class="num">5].name = "alignmentWeight"; params [class="num">5].val = alignmentWeight; params [class="num">6].name = "alignmentDist"; params [class="num">6].val = alignmentDist; params [class="num">7].name = "maxSpeed"; params [class="num">7].val = maxSpeed; params [class="num">8].name = "minSpeed"; params [class="num">8].val = minSpeed; params [class="num">9].name = "learningRate"; params [class="num">9].val = learningRate; params [class="num">10].name = "neuralInfluence"; params [class="num">10].val = neuralInfluence; params [class="num">11].name = "explorationRate"; params [class="num">11].val = explorationRate; class=class="str">"cmt">// Initialize the stagnation counter and the previous best fitness value m_stagnationCounter = class="num">0; m_prevBestFitness = -DBL_MAX; } class="type">void SetParams() { popSize = (class="type">int)params [class="num">0].val; cohesionWeight = params [class="num">1].val; cohesionDist = params [class="num">2].val; separationWeight = params [class="num">3].val; separationDist = params [class="num">4].val; alignmentWeight = params [class="num">5].val; alignmentDist = params [class="num">6].val; maxSpeed = params [class="num">7].val;
NeuroBoids 智能体的参数与私有方法布局
这段结构定义了一个基于群体行为(boids)的代理系统,参数从 params 数组的第 8 到第 11 索引读取:minSpeed 控制最小速度,learningRate 是神经网络学习速率,neuralInfluence 决定网络对运动的干预强度,explorationRate 则是随机探索概率。 公开字段里能看到三类经典群体规则权重与距离:cohesion(聚合)、separation(分离)、alignment(对齐),各自配了 weight 和 dist 双变量;maxSpeed 与 minSpeed 框定个体速率上下限,m_stagnationCounter 和 m_prevBestFitness 用来跟踪优化停滞。 私有段暴露了实际计算链路:CalculateMass 算质量,Cohesion/Separation/Alignment 是三条规则实现,LimitSpeed 与 KeepWithinBounds 做边界约束,Distance 提供两两距离,ApplyNeuralControl 把神经网络输出灌进运动决策。 在 MT5 里若想调敏感性,优先动 params[10](neuralInfluence)和 params[11](explorationRate):前者偏高会让价格模拟更依赖网络推断,后者偏高则增加随机扰动,外汇与贵金属市场波动剧烈,这类参数组合需先在历史数据回测验证稳定性。
minSpeed = params [class="num">8].val; learningRate = params [class="num">9].val; neuralInfluence = params [class="num">10].val; explorationRate = params [class="num">11].val; } class="type">bool Init(const class="type">class="kw">double &rangeMinP [], const class="type">class="kw">double &rangeMaxP [], const class="type">class="kw">double &rangeStepP [], const class="type">int epochsP = class="num">0); class="type">void Moving(); class="type">void Revision(); class=class="str">"cmt">//---------------------------------------------------------------------------- class="type">class="kw">double cohesionWeight; class=class="str">"cmt">// cohesion weight class="type">class="kw">double cohesionDist; class=class="str">"cmt">// cohesion distance class="type">class="kw">double separationWeight; class=class="str">"cmt">// separation weight class="type">class="kw">double separationDist; class=class="str">"cmt">// separation distance class="type">class="kw">double alignmentWeight; class=class="str">"cmt">// alignment weight class="type">class="kw">double alignmentDist; class=class="str">"cmt">// alignment distance class="type">class="kw">double minSpeed; class=class="str">"cmt">// minimum speed class="type">class="kw">double maxSpeed; class=class="str">"cmt">// maximum speed class="type">class="kw">double learningRate; class=class="str">"cmt">// neural network learning speed class="type">class="kw">double neuralInfluence; class=class="str">"cmt">// influence of the neural network on movement class="type">class="kw">double explorationRate; class=class="str">"cmt">// random exploration probability class="type">int m_stagnationCounter; class=class="str">"cmt">// stagnation counter class="type">class="kw">double m_prevBestFitness; class=class="str">"cmt">// previous best fitness value S_NeuroBoids_Agent agent []; class=class="str">"cmt">// agents(boids) class="kw">private: class=class="str">"cmt">//------------------------------------------------------------------- class="type">class="kw">double distanceMax; class=class="str">"cmt">// maximum distance class="type">class="kw">double speedMax []; class=class="str">"cmt">// maximum speeds by measurements class="type">int neuron_size; class=class="str">"cmt">// neuron size(number of inputs) class="type">void CalculateMass(); class=class="str">"cmt">// calculation of agent masses class="type">void Cohesion(S_NeuroBoids_Agent &boid, class="type">int pos); class=class="str">"cmt">// cohesion rule class="type">void Separation(S_NeuroBoids_Agent &boid, class="type">int pos); class=class="str">"cmt">// separation rule class="type">void Alignment(S_NeuroBoids_Agent &boid, class="type">int pos); class=class="str">"cmt">// alignment rule class="type">void LimitSpeed(S_NeuroBoids_Agent &boid); class=class="str">"cmt">// speed limit class="type">void KeepWithinBounds(S_NeuroBoids_Agent &boid); class=class="str">"cmt">// keep within bounds class="type">class="kw">double Distance(S_NeuroBoids_Agent &boid1, S_NeuroBoids_Agent &boid2); class=class="str">"cmt">// calculate distance class="type">void ApplyNeuralControl(S_NeuroBoids_Agent &boid, class="type">int pos); class=class="str">"cmt">// apply neural control
「初始化里的群体参数落地」
C_AO_NOA2::Init 负责把外部传入的搜索区间和步长接住,先调 StandardInit 做基础校验,失败直接返 false。随后按 coords*2+2 算神经元尺寸——多出的两项留给到最优点的距离与当前适应度,这是后面个体移动时的关键状态位。 种群代理用 ArrayResize(agent, popSize) 开好,再逐个 Init(coords, neuron_size)。distanceMax 不是拍脑袋给的,而是遍历各维度 speedMax[c]=rangeMax[c]-rangeMin[c],平方和开根得出,代表解空间对角线长度,后续速度归一化会用到。
- 个群体行为参数(凝聚、分离、对齐权重与距离,最大最小速度,学习率,神经影响,探索率)全部写进全局变量,键名带数字前缀方便 EA 其他模块读取。m_stagnationCounter 清零、m_prevBestFitness 设 -DBL_MAX,相当于把停滞保护机制重置回冷启动状态。
外汇与贵金属市场波动剧烈、杠杆风险高,这类群体优化器参数若未随品种波动率重标定,搜索可能长期偏离实盘可行域。开 MT5 把 Init 里的 rangeMin/rangeMax 换成 EURUSD 的 ATR(14) 区间跑一次,能直接看出 popSize 与 epochs 对收敛速度的影响。
class="type">bool C_AO_NOA2::Init(const class="type">class="kw">double &rangeMinP [], class=class="str">"cmt">// minimum search range const class="type">class="kw">double &rangeMaxP [], class=class="str">"cmt">// maximum search range const class="type">class="kw">double &rangeStepP [], class=class="str">"cmt">// search step const class="type">int epochsP) class=class="str">"cmt">// number of epochs { if (!StandardInit(rangeMinP, rangeMaxP, rangeStepP)) class="kw">return false; class=class="str">"cmt">// Determine the size of a neuron neuron_size = coords * class="num">2 + class="num">2; class=class="str">"cmt">// x, dx, dist_to_best, current_fitness class=class="str">"cmt">// Initialize the agents ArrayResize(agent, popSize); for (class="type">int i = class="num">0; i < popSize; i++) { agent [i].Init(coords, neuron_size); } distanceMax = class="num">0; ArrayResize(speedMax, coords); for (class="type">int c = class="num">0; c < coords; c++) { speedMax [c] = rangeMax [c] - rangeMin [c]; distanceMax += MathPow(speedMax [c], class="num">2); } distanceMax = MathSqrt(distanceMax); class=class="str">"cmt">// Reset the stagnation counter and the previous best fitness value m_stagnationCounter = class="num">0; m_prevBestFitness = -DBL_MAX; GlobalVariableSet("class="macro">#reset", class="num">1.0); GlobalVariableSet("1cohesionWeight", params [class="num">1].val); GlobalVariableSet("2cohesionDist", params [class="num">2].val); GlobalVariableSet("3separationWeight", params [class="num">3].val); GlobalVariableSet("4separationDist", params [class="num">4].val); GlobalVariableSet("5alignmentWeight", params [class="num">5].val); GlobalVariableSet("6alignmentDist", params [class="num">6].val); GlobalVariableSet("7maxSpeed", params [class="num">7].val); GlobalVariableSet("8minSpeed", params [class="num">8].val); GlobalVariableSet("9learningRate", params [class="num">9].val); GlobalVariableSet("10neuralInfluence", params [class="num">10].val); GlobalVariableSet("11explorationRate", params [class="num">11].val); class="kw">return true; }
◍ 用全局变量接管群体参数的初始化与步进
这段逻辑把算法的交互配置完全挂到 MT5 全局变量上,外部脚本或面板改一个值,EA 下一 tick 就能读到。注意变量名用数字前缀(如 "1cohesionWeight")只是为了避免命名冲突,GlobalVariableGet 拿到的就是实时权重,不需要重编译。 revision 标志控制是否冷启动。第一次跑的时候 revision=false,代码会给每个 agent 在 rangeMin~rangeMax 区间内撒随机坐标,速度则取区间跨度乘 ±1 的随机值再乘 0.001,也就是初始扰动被压到千分之一量级,避免一上来就乱飞。
revision = false; GlobalVariableSet("class="macro">#reset", class="num">0.0); } class=class="str">"cmt">// Get parameters from global variables for interactive configuration cohesionWeight = GlobalVariableGet("1cohesionWeight"); cohesionDist = GlobalVariableGet("2cohesionDist"); separationWeight = GlobalVariableGet("3separationWeight"); separationDist = GlobalVariableGet("4separationDist"); alignmentWeight = GlobalVariableGet("5alignmentWeight"); alignmentDist = GlobalVariableGet("6alignmentDist"); maxSpeed = GlobalVariableGet("7maxSpeed"); minSpeed = GlobalVariableGet("8minSpeed"); learningRate = GlobalVariableGet("9learningRate"); neuralInfluence = GlobalVariableGet("10neuralInfluence"); explorationRate = GlobalVariableGet("11explorationRate"); class=class="str">"cmt">// Initialization of initial positions and speeds if (!revision) { for (class="type">int i = class="num">0; i < popSize; i++) { for (class="type">int c = class="num">0; c < coords; c++) { agent [i].x [c] = u.RNDfromCI(rangeMin [c], rangeMax [c]); agent [i].dx [c] = (rangeMax [c] - rangeMin [c]) * u.RNDfromCI(-class="num">1.0, class="num">1.0) * class="num">0.001; a [i].c [c] = u.SeInDiSp(agent [i].x [c], rangeMin [c], rangeMax [c], rangeStep [c]); } } revision = true; class="kw">return; } class=class="str">"cmt">// Adaptive research depending on stagnation AdaptiveExploration(); class=class="str">"cmt">//---------------------------------------------------------------------------- class=class="str">"cmt">// Main loop of boid movement for (class="type">int i = class="num">0; i < popSize; i++) { class=class="str">"cmt">// Save the current experience agent [i].MemorizeExperience(a [i].f, coords); class=class="str">"cmt">// Update the agent&class="macro">#x27;s best position agent [i].UpdateBestPosition(a [i].f, coords); class=class="str">"cmt">// Update the neural network inputs agent [i].UpdateInputs(cB, a [i].f, coords); class=class="str">"cmt">// Forward propagation through the neural network agent [i].ForwardPass(coords); class=class="str">"cmt">// Learning from accumulated experience agent [i].Learn(learningRate, coords); } class=class="str">"cmt">// Calculate masses CalculateMass(); class=class="str">"cmt">// Application of rules and movement for (class="type">int i = class="num">0; i < popSize; i++) { class=class="str">"cmt">// Standard rules of the boid algorithm Cohesion(agent [i], i); Separation(agent [i], i); Alignment(agent [i], i); class=class="str">"cmt">// Apply neural control ApplyNeuralControl(agent [i], i); class=class="str">"cmt">// Speed limit and keeping within bounds LimitSpeed(agent [i]); KeepWithinBounds(agent [i]); class=class="str">"cmt">// Update positions for (class="type">int c = class="num">0; c < coords; c++) { agent [i].x [c] += agent [i].dx [c]; a [i].c [c] = u.SeInDiSp(agent [i].x [c], rangeMin [c], rangeMax [c], rangeStep [c]); } } } class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class="type">void C_AO_NOA2::CalculateMass()
revision = false; GlobalVariableSet("class="macro">#reset", class="num">0.0); } class=class="str">"cmt">// Get parameters from global variables for interactive configuration cohesionWeight = GlobalVariableGet("1cohesionWeight"); cohesionDist = GlobalVariableGet("2cohesionDist"); separationWeight = GlobalVariableGet("3separationWeight"); separationDist = GlobalVariableGet("4separationDist"); alignmentWeight = GlobalVariableGet("5alignmentWeight"); alignmentDist = GlobalVariableGet("6alignmentDist"); maxSpeed = GlobalVariableGet("7maxSpeed"); minSpeed = GlobalVariableGet("8minSpeed"); learningRate = GlobalVariableGet("9learningRate"); neuralInfluence = GlobalVariableGet("10neuralInfluence"); explorationRate = GlobalVariableGet("11explorationRate"); class=class="str">"cmt">// Initialization of initial positions and speeds if (!revision) { for (class="type">int i = class="num">0; i < popSize; i++) { for (class="type">int c = class="num">0; c < coords; c++) { agent [i].x [c] = u.RNDfromCI(rangeMin [c], rangeMax [c]); agent [i].dx [c] = (rangeMax [c] - rangeMin [c]) * u.RNDfromCI(-class="num">1.0, class="num">1.0) * class="num">0.001; a [i].c [c] = u.SeInDiSp(agent [i].x [c], rangeMin [c], rangeMax [c], rangeStep [c]); } } revision = true; class="kw">return; } class=class="str">"cmt">// Adaptive research depending on stagnation AdaptiveExploration(); class=class="str">"cmt">//---------------------------------------------------------------------------- class=class="str">"cmt">// Main loop of boid movement for (class="type">int i = class="num">0; i < popSize; i++) { class=class="str">"cmt">// Save the current experience agent [i].MemorizeExperience(a [i].f, coords); class=class="str">"cmt">// Update the agent&class="macro">#x27;s best position agent [i].UpdateBestPosition(a [i].f, coords); class=class="str">"cmt">// Update the neural network inputs agent [i].UpdateInputs(cB, a [i].f, coords); class=class="str">"cmt">// Forward propagation through the neural network agent [i].ForwardPass(coords); class=class="str">"cmt">// Learning from accumulated experience agent [i].Learn(learningRate, coords); } class=class="str">"cmt">// Calculate masses CalculateMass(); class=class="str">"cmt">// Application of rules and movement for (class="type">int i = class="num">0; i < popSize; i++) { class=class="str">"cmt">// Standard rules of the boid algorithm Cohesion(agent [i], i); Separation(agent [i], i); Alignment(agent [i], i); class=class="str">"cmt">// Apply neural control ApplyNeuralControl(agent [i], i); class=class="str">"cmt">// Speed limit and keeping within bounds LimitSpeed(agent [i]); KeepWithinBounds(agent [i]); class=class="str">"cmt">// Update positions for (class="type">int c = class="num">0; c < coords; c++) { agent [i].x [c] += agent [i].dx [c]; a [i].c [c] = u.SeInDiSp(agent [i].x [c], rangeMin [c], rangeMax [c], rangeStep [c]); } } } class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class="type">void C_AO_NOA2::CalculateMass()
把神经网络输出接进群体搜索的实操段
这段代码把神经网络的输出直接叠加到 boid 的速度分量上,再按输出自适应缩放聚合、分离、对齐三类权重。注意叠加前用 ArraySize 做了边界保护,c 超出 outputs 长度就不改对应 dx,避免 EA 在参数维度不匹配时直接越界崩掉。 局部权重计算用了 0.5 作基线:local_cohesion = cohesionWeight * (0.5 + cohesion_factor),也就是神经输出为 0 时只保留一半基础权重,输出到 0.5 才回到原始权重。这种写法让网络对群体行为的干预是渐进的,不会一上来就颠覆原算法。 停滞检测那段给了明确阈值:当最优适应度变化小于 0.000001 时计数加一,连续超过 20 代才触发探索概率提升。外汇与贵金属市场波动突变频繁,把 20 和 0.000001 直接抄进 MT5 回测,看你的品种在横盘期会不会过早放大随机扰动。 探索扰动幅度跟个体质量挂钩:(1.0 - boid.m) 意味着适应度越低的 agent 被扰得越狠,高质量个体几乎不动。m 来自上一段把适应度缩放到 0.1~1.0 的结果,所以最差个体扰动系数接近 0.9 倍量程的 1%,最优个体只有 0.1 倍。
class="type">class="kw">double maxMass = -DBL_MAX; class="type">class="kw">double minMass = DBL_MAX; class=class="str">"cmt">// Check for data presence before calculations if (popSize <= class="num">0) class="kw">return; for (class="type">int i = class="num">0; i < popSize; i++) { if (a [i].f > maxMass) maxMass = a [i].f; if (a [i].f < minMass) minMass = a [i].f; } for (class="type">int i = class="num">0; i < popSize; i++) { agent [i].m = u.Scale(a [i].f, minMass, maxMass, class="num">0.1, class="num">1.0); } } class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class=class="str">"cmt">// Apply neural control to a boid class="type">void C_AO_NOA2::ApplyNeuralControl(S_NeuroBoids_Agent &boid, class="type">int pos) { class=class="str">"cmt">// Use the neural network outputs to correct the speed for (class="type">int c = class="num">0; c < coords; c++) { class=class="str">"cmt">// Make sure the index is not outside the array bounds if (c < ArraySize(boid.outputs)) { class=class="str">"cmt">// Apply neural speed correction with a given influence boid.dx [c] += boid.outputs [c] * neuralInfluence; } } class=class="str">"cmt">// Use the neural network outputs to adapt the flock parameters class=class="str">"cmt">// Check that the indices do not go beyond the array bounds class="type">int output_size = ArraySize(boid.outputs); class="type">class="kw">double cohesion_factor = (coords < output_size) ? boid.outputs [coords] : class="num">0.5; class="type">class="kw">double separation_factor = (coords + class="num">1 < output_size) ? boid.outputs [coords + class="num">1] : class="num">0.5; class="type">class="kw">double alignment_factor = (coords + class="num">2 < output_size) ? boid.outputs [coords + class="num">2] : class="num">0.5; class=class="str">"cmt">// Scale the base weights considering neural adaptation class=class="str">"cmt">// These variables are local and do not change global parameters class="type">class="kw">double local_cohesion = cohesionWeight * (class="num">0.5 + cohesion_factor); class="type">class="kw">double local_separation = separationWeight * (class="num">0.5 + separation_factor); class="type">class="kw">double local_alignment = alignmentWeight * (class="num">0.5 + alignment_factor); class=class="str">"cmt">// Random study with a given probability if (u.RNDprobab() < explorationRate) { class=class="str">"cmt">// Select a random coordinate for perturbation class="type">int c = (class="type">int)u.RNDfromCI(class="num">0, coords - class="num">1); class=class="str">"cmt">// Adaptive perturbation size depending on mass(fitness) class="type">class="kw">double perturbation_size = (class="num">1.0 - boid.m) * (rangeMax [c] - rangeMin [c]) * class="num">0.01; class=class="str">"cmt">// Add random perturbation boid.dx [c] += u.RNDfromCI(-perturbation_size, perturbation_size); } } class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class=class="str">"cmt">// Adaptive research depending on stagnation class="type">void C_AO_NOA2::AdaptiveExploration() { class=class="str">"cmt">// Determine if there is progress in the search if (MathAbs(fB - m_prevBestFitness) < class="num">0.000001) { m_stagnationCounter++; } else { m_stagnationCounter = class="num">0; m_prevBestFitness = fB; } class=class="str">"cmt">// Increase research during stagnation if (m_stagnationCounter > class="num">20) { class=class="str">"cmt">// Increase the probability of random exploration