322 lines
15 KiB
MQL5
322 lines
15 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| D2SkillBankStudy.mq5 |
|
|
//| Standalone D2Skill bank lifecycle acceptance study. |
|
|
//+------------------------------------------------------------------+
|
|
#property strict
|
|
#property version "1.00"
|
|
|
|
#include "..\\NeuroNet_DNG\\NeuroNet.mqh"
|
|
|
|
const uint D2_STUDY_DIM = 2;
|
|
const uint D2_STUDY_SLOTS = 2;
|
|
const float D2_STUDY_EPSILON = 0.000001f;
|
|
const string D2_STUDY_FILE = "D2SkillBankStudy.bin";
|
|
|
|
CNet g_net;
|
|
CNeuronBaseOCL g_source;
|
|
bool g_completed = false;
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CreateHost(void)
|
|
{
|
|
CArrayObj *description = new CArrayObj();
|
|
if(!description)
|
|
ReturnFalse;
|
|
description.FreeMode(true);
|
|
for(int i = 0; i < 2; i++)
|
|
{
|
|
CLayerDescription *layer = new CLayerDescription();
|
|
if(!layer)
|
|
{
|
|
DeleteObjAndFalse(description);
|
|
}
|
|
layer.type = defNeuronBaseOCL;
|
|
layer.count = D2_STUDY_DIM;
|
|
layer.activation = None;
|
|
layer.optimization = ADAM;
|
|
if(!description.Add(layer))
|
|
{
|
|
DeleteObj(layer);
|
|
DeleteObjAndFalse(description);
|
|
}
|
|
}
|
|
const bool created = g_net.Create(description);
|
|
delete description;
|
|
return(created && g_net.GetOpenCL() != NULL);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool Put(CBufferFloat *buffer, const float first, const float second)
|
|
{
|
|
float values[2] = {first, second};
|
|
return(buffer && buffer.AssignArray(values) && buffer.BufferWrite());
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool ReadSelection(CD2SkillBank &bank)
|
|
{
|
|
return(bank.SelectedSlot().BufferRead() && bank.SelectedScore().BufferRead() &&
|
|
bank.SelectedCorrection().BufferRead());
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Confirmation data use a stable account-side query. |
|
|
//+------------------------------------------------------------------+
|
|
bool Train(CD2SkillBank &bank, const float gradient_x, const float gradient_y)
|
|
{
|
|
if(!Put(g_source.getOutput(), 1.0f, 0.0f) || !bank.FeedForward(g_source.AsObject()) ||
|
|
!Put(g_source.getGradient(), gradient_x, gradient_y) ||
|
|
!bank.UpdateFromGradient(g_source.getOutput(), g_source.getGradient()))
|
|
ReturnFalse;
|
|
return(true);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool ReadLifecycle(CD2SkillBank &bank)
|
|
{
|
|
return(bank.RefreshDiagnostics() && bank.Diagnostics().BufferRead() &&
|
|
bank.Used().BufferRead() && bank.State().BufferRead());
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Two close keys intentionally own corrections with opposite sign.|
|
|
//+------------------------------------------------------------------+
|
|
bool SeedCloseOpposingCorrections(CD2SkillBank &bank)
|
|
{
|
|
float keys[4] = {1.00f, 0.00f, 0.98f, 0.20f};
|
|
float corrections[4] = {0.40f, 0.00f, -0.40f, 0.00f};
|
|
float directions[4] = {1.00f, 0.00f, -1.00f, 0.00f};
|
|
float scales[2] = {0.40f, 0.40f};
|
|
float utility[2] = {0.00f, 0.00f};
|
|
float observations[2] = {2.00f, 2.00f};
|
|
float uses[2] = {0.00f, 0.00f};
|
|
float mass[2] = {1.00f, 1.00f};
|
|
float used[2] = {1.00f, 1.00f};
|
|
float states[2] = {(float)D2SKILL_ACTIVE, (float)D2SKILL_ACTIVE};
|
|
float ages[2] = {0.00f, 0.00f};
|
|
float protection[2] = {0.00f, 0.00f};
|
|
float influence[2] = {0.00f, 0.00f};
|
|
return(bank.Keys().AssignArray(keys) && bank.Keys().BufferWrite() &&
|
|
bank.Corrections().AssignArray(corrections) && bank.Corrections().BufferWrite() &&
|
|
bank.Directions().AssignArray(directions) && bank.Directions().BufferWrite() &&
|
|
bank.Scales().AssignArray(scales) && bank.Scales().BufferWrite() &&
|
|
bank.Utility().AssignArray(utility) && bank.Utility().BufferWrite() &&
|
|
bank.ObservationsBank().AssignArray(observations) && bank.ObservationsBank().BufferWrite() &&
|
|
bank.Uses().AssignArray(uses) && bank.Uses().BufferWrite() &&
|
|
bank.MassBank().AssignArray(mass) && bank.MassBank().BufferWrite() &&
|
|
bank.Used().AssignArray(used) && bank.Used().BufferWrite() &&
|
|
bank.State().AssignArray(states) && bank.State().BufferWrite() &&
|
|
bank.Ages().AssignArray(ages) && bank.Ages().BufferWrite() &&
|
|
bank.Protection().AssignArray(protection) && bank.Protection().BufferWrite() &&
|
|
bank.Influence().AssignArray(influence) && bank.Influence().BufferWrite());
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Nearby account states must select their matching signed residual.|
|
|
//+------------------------------------------------------------------+
|
|
bool RunCorrectionSelection(void)
|
|
{
|
|
CD2SkillBank bank;
|
|
if(!bank.Init(D2_STUDY_DIM, 100, g_net.GetOpenCL(), D2_STUDY_SLOTS, ADAM, 1) ||
|
|
!bank.SetThresholds(0.50f, 0.50f) || !bank.SetAlpha(1.00f) ||
|
|
!bank.SetUtilityPolicy(false, -1.00f) || !bank.SetEnabled(true) ||
|
|
!SeedCloseOpposingCorrections(bank))
|
|
ReturnFalse;
|
|
if(!Put(g_source.getOutput(), 1.00f, 0.00f) || !bank.FeedForward(g_source.AsObject()) ||
|
|
!ReadSelection(bank))
|
|
ReturnFalse;
|
|
const float aligned_slot = bank.SelectedSlot()[0];
|
|
const float aligned_correction = bank.SelectedCorrection()[0];
|
|
if(!Put(g_source.getOutput(), 0.98f, 0.20f) || !bank.FeedForward(g_source.AsObject()) ||
|
|
!ReadSelection(bank))
|
|
ReturnFalse;
|
|
const float opposing_slot = bank.SelectedSlot()[0];
|
|
const float opposing_correction = bank.SelectedCorrection()[0];
|
|
PrintFormat("D2SkillBankStudy: corrections aligned_slot=%.0f aligned=%.4f "
|
|
"opposing_slot=%.0f opposing=%.4f",
|
|
aligned_slot, aligned_correction, opposing_slot, opposing_correction);
|
|
return(aligned_slot == 0.0f && aligned_correction > 0.0f &&
|
|
opposing_slot == 1.0f && opposing_correction < 0.0f);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Candidate becomes an ordinary slot, then evicts only inactive. |
|
|
//+------------------------------------------------------------------+
|
|
bool RunCandidateAndEviction(void)
|
|
{
|
|
CD2SkillBank bank;
|
|
if(!bank.Init(D2_STUDY_DIM, 200, g_net.GetOpenCL(), D2_STUDY_SLOTS, ADAM, 1) ||
|
|
!bank.SetThresholds(0.80f, 0.80f) || !bank.SetLifecycle(2, 0, 2) ||
|
|
!bank.SetUtilityPolicy(false, -1.00f) || !bank.SetEnabled(true) ||
|
|
!Train(bank, 1.00f, 0.00f) || !Train(bank, 1.00f, 0.00f) ||
|
|
!Train(bank, -1.00f, 0.00f) || !Train(bank, -1.00f, 0.00f) ||
|
|
!Train(bank, 0.00f, 1.00f) || !Train(bank, 0.00f, 1.00f) ||
|
|
!ReadLifecycle(bank))
|
|
ReturnFalse;
|
|
const float candidate_before = bank.Diagnostics()[10];
|
|
const float evicted_before = bank.Diagnostics()[7];
|
|
if(candidate_before != 1.0f || evicted_before != 0.0f)
|
|
ReturnFalse;
|
|
if(!Train(bank, 0.00f, 1.00f) || !ReadLifecycle(bank))
|
|
ReturnFalse;
|
|
const float evicted_after = bank.Diagnostics()[7];
|
|
const float inactive_after = bank.Diagnostics()[13];
|
|
PrintFormat("D2SkillBankStudy: candidate candidate=%.0f evicted_before=%.0f "
|
|
"evicted_after=%.0f inactive_after=%.0f",
|
|
candidate_before, evicted_before, evicted_after, inactive_after);
|
|
return(evicted_after >= 1.0f && inactive_after <= 1.0f);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| A promoted DirectionMagnitude candidate keeps scale as its norm. |
|
|
//+------------------------------------------------------------------+
|
|
bool RunDirectionMagnitudePromotion(void)
|
|
{
|
|
CD2SkillBank bank;
|
|
if(!bank.Init(D2_STUDY_DIM, 250, g_net.GetOpenCL(), D2_STUDY_SLOTS, ADAM, 1) ||
|
|
!bank.SetThresholds(0.80f, -1.00f) || !bank.SetLifecycle(2, 0, 2) ||
|
|
!bank.SetMaxCorrection(10.00f) || !bank.SetUtilityPolicy(false, -1.00f) ||
|
|
!bank.SetEnabled(true) || !Train(bank, 1.00f, 0.00f) ||
|
|
!Train(bank, 1.00f, 1.00f) || !Put(g_source.getOutput(), 1.00f, 0.00f) ||
|
|
!bank.FeedForward(g_source.AsObject()) || !ReadSelection(bank) ||
|
|
!bank.Directions().BufferRead() || !bank.Scales().BufferRead())
|
|
ReturnFalse;
|
|
const int slot = (int)bank.SelectedSlot()[0];
|
|
if(slot < 0 || slot >= (int)D2_STUDY_SLOTS)
|
|
ReturnFalse;
|
|
const int offset = slot * (int)D2_STUDY_DIM;
|
|
const float direction_norm = (float)MathSqrt(bank.Directions()[offset] *
|
|
bank.Directions()[offset] + bank.Directions()[offset + 1] *
|
|
bank.Directions()[offset + 1]);
|
|
const float correction_norm = (float)MathSqrt(bank.SelectedCorrection()[0] *
|
|
bank.SelectedCorrection()[0] + bank.SelectedCorrection()[1] *
|
|
bank.SelectedCorrection()[1]);
|
|
const float scale = bank.Scales()[slot];
|
|
PrintFormat("D2SkillBankStudy: direction_magnitude slot=%d direction_norm=%.8f "
|
|
"correction_norm=%.8f scale=%.8f", slot, direction_norm,
|
|
correction_norm, scale);
|
|
return(MathAbs(direction_norm - 1.00f) <= D2_STUDY_EPSILON &&
|
|
MathAbs(correction_norm - scale) <= D2_STUDY_EPSILON);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Protected slots reject an unrelated confirmed candidate. |
|
|
//+------------------------------------------------------------------+
|
|
bool RunProtectedRejection(void)
|
|
{
|
|
CD2SkillBank bank;
|
|
if(!bank.Init(D2_STUDY_DIM, 300, g_net.GetOpenCL(), D2_STUDY_SLOTS, ADAM, 1) ||
|
|
!bank.SetThresholds(0.80f, 0.80f) || !bank.SetLifecycle(2, 100, 1000) ||
|
|
!bank.SetUtilityPolicy(false, -1.00f) || !bank.SetEnabled(true) ||
|
|
!Train(bank, 1.00f, 0.00f) || !Train(bank, 1.00f, 0.00f) ||
|
|
!Train(bank, -1.00f, 0.00f) || !Train(bank, -1.00f, 0.00f) ||
|
|
!Train(bank, 0.00f, 1.00f) || !Train(bank, 0.00f, 1.00f) ||
|
|
!ReadLifecycle(bank))
|
|
ReturnFalse;
|
|
const float rejected = bank.Diagnostics()[5];
|
|
const float evicted = bank.Diagnostics()[7];
|
|
const float protected_slots = bank.Diagnostics()[11];
|
|
PrintFormat("D2SkillBankStudy: protected rejected=%.0f evicted=%.0f protected=%.0f",
|
|
rejected, evicted, protected_slots);
|
|
return(rejected >= 1.0f && evicted == 0.0f && protected_slots == D2_STUDY_SLOTS);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| A query outside the acceptance gate must take the zero NoSkill path.|
|
|
//+------------------------------------------------------------------+
|
|
bool RunNoSkill(void)
|
|
{
|
|
CD2SkillBank bank;
|
|
if(!bank.Init(D2_STUDY_DIM, 400, g_net.GetOpenCL(), D2_STUDY_SLOTS, ADAM, 1) ||
|
|
!bank.SetThresholds(0.50f, 0.50f) || !bank.SetUtilityPolicy(false, -1.00f) ||
|
|
!bank.SetEnabled(true) || !SeedCloseOpposingCorrections(bank) ||
|
|
!Put(g_source.getOutput(), -1.00f, 0.00f) || !bank.FeedForward(g_source.AsObject()) ||
|
|
!ReadSelection(bank))
|
|
ReturnFalse;
|
|
const float correction_norm = bank.SelectedCorrection()[0] * bank.SelectedCorrection()[0] +
|
|
bank.SelectedCorrection()[1] * bank.SelectedCorrection()[1];
|
|
PrintFormat("D2SkillBankStudy: noskill slot=%.0f correction_norm=%.8f",
|
|
bank.SelectedSlot()[0], correction_norm);
|
|
return(bank.SelectedSlot()[0] == -1.0f && correction_norm <= D2_STUDY_EPSILON);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Save/Load preserves durable slots and gives the same next winner.|
|
|
//+------------------------------------------------------------------+
|
|
bool RunPersistenceWinner(void)
|
|
{
|
|
CD2SkillBank original;
|
|
if(!original.Init(D2_STUDY_DIM, 500, g_net.GetOpenCL(), D2_STUDY_SLOTS, ADAM, 1) ||
|
|
!original.SetThresholds(0.50f, 0.50f) || !original.SetAlpha(1.00f) ||
|
|
!original.SetUtilityPolicy(false, -1.00f) || !original.SetEnabled(true) ||
|
|
!SeedCloseOpposingCorrections(original) || !Put(g_source.getOutput(), 0.98f, 0.20f) ||
|
|
!original.FeedForward(g_source.AsObject()) || !ReadSelection(original))
|
|
ReturnFalse;
|
|
const float expected_slot = original.SelectedSlot()[0];
|
|
const float expected_score = original.SelectedScore()[0];
|
|
const float expected_correction = original.SelectedCorrection()[0];
|
|
int handle = FileOpen(D2_STUDY_FILE, FILE_WRITE | FILE_BIN | FILE_COMMON);
|
|
if(handle == INVALID_HANDLE)
|
|
ReturnFalse;
|
|
if(!original.Save(handle))
|
|
{
|
|
FileClose(handle);
|
|
ReturnFalse;
|
|
}
|
|
FileClose(handle);
|
|
CD2SkillBank restored;
|
|
handle = FileOpen(D2_STUDY_FILE, FILE_READ | FILE_BIN | FILE_COMMON | FILE_SHARE_READ);
|
|
if(handle == INVALID_HANDLE)
|
|
ReturnFalse;
|
|
if(!restored.Load(handle, g_net.GetOpenCL()))
|
|
{
|
|
FileClose(handle);
|
|
ReturnFalse;
|
|
}
|
|
FileClose(handle);
|
|
if(!Put(g_source.getOutput(), 0.98f, 0.20f) || !restored.FeedForward(g_source.AsObject()) ||
|
|
!ReadSelection(restored))
|
|
ReturnFalse;
|
|
const float slot_delta = MathAbs(restored.SelectedSlot()[0] - expected_slot);
|
|
const float score_delta = MathAbs(restored.SelectedScore()[0] - expected_score);
|
|
const float correction_delta = MathAbs(restored.SelectedCorrection()[0] - expected_correction);
|
|
PrintFormat("D2SkillBankStudy: persistence winner=%.0f slot_delta=%.8f "
|
|
"score_delta=%.8f correction_delta=%.8f",
|
|
restored.SelectedSlot()[0], slot_delta, score_delta, correction_delta);
|
|
return(slot_delta <= D2_STUDY_EPSILON && score_delta <= D2_STUDY_EPSILON &&
|
|
correction_delta <= D2_STUDY_EPSILON);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
int OnInit(void)
|
|
{
|
|
if(!CreateHost() ||
|
|
!g_source.Init(0, 10, g_net.GetOpenCL(), D2_STUDY_DIM, ADAM, 1) ||
|
|
!RunCorrectionSelection() || !RunCandidateAndEviction() ||
|
|
!RunDirectionMagnitudePromotion() ||
|
|
!RunProtectedRejection() || !RunNoSkill() || !RunPersistenceWinner())
|
|
{
|
|
PrintFormat("D2SkillBankStudy: FAIL error=%d", GetLastError());
|
|
return(INIT_FAILED);
|
|
}
|
|
Print("D2SkillBankStudy: PASS corrections candidate direction protected eviction noskill persistence");
|
|
g_completed = true;
|
|
if(!EventSetMillisecondTimer(1))
|
|
return(INIT_FAILED);
|
|
return(INIT_SUCCEEDED);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void OnTimer(void)
|
|
{
|
|
if(g_completed)
|
|
ExpertRemove();
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void OnDeinit(const int reason)
|
|
{
|
|
EventKillTimer();
|
|
g_source.Clear();
|
|
}
|
|
//+------------------------------------------------------------------+
|