2026-08-18 19:58:41 +03:00 | | | //+------------------------------------------------------------------+
|
2026-08-20 22:59:48 +03:00 | | | //| NeuroNet_D2Skill.mqh |
|
| | | //| GPU-resident D2Skill primitives |
|
2026-08-18 19:58:41 +03:00 | | | //+------------------------------------------------------------------+
|
| | | #ifndef NEURONET_D2SKILL_MQH
|
| | | #define NEURONET_D2SKILL_MQH
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Reuse boundary: D2Skill keeps its own flat GPU bank because its |
|
| | | //| signed corrections, direction agreement, utility/age eviction, |
|
| | | //| candidate promotion and Task/Step dual routing are not |
|
| | | //| represented by CScenarioCodebook. RAG score/Top-K and persistence|
|
| | | //| conventions are reused where their contracts match; |
|
| | | //| CNeuronRAGMemory is intentionally not used because its publish |
|
| | | //| path is CPU copy-on-write plus re-upload. |
|
2026-08-18 19:58:41 +03:00 | | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | void CD2SkillItem::RebindItemBuffer(CBufferFloat &buffer, COpenCLMy *obj)
|
| | | {
|
| | | if(!obj)
|
| | | return;
|
| | | if(buffer.GetOpenCL() != NULL && buffer.GetIndex() >= 0)
|
| | | buffer.BufferFree();
|
| | | if(buffer.Total() > 0)
|
2026-08-18 19:58:41 +03:00 | | | buffer.BufferCreate(obj);
|
2026-08-20 19:55:53 +03:00 | | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Constructor: initializes the correction pointer, representation |
|
| | | //| mode and EMA smoothing defaults. |
|
2026-08-20 22:59:48 +03:00 | | | //+------------------------------------------------------------------+
|
| | | void CD2SkillItem::CD2SkillItem(void) : m_correction(NULL),
|
2026-08-20 19:55:53 +03:00 | | | m_representation(D2SkillDirectionMagnitude),
|
| | | m_beta_correction(0.05f), m_beta_direction(0.05f),
|
| | | m_beta_magnitude(0.05f), m_item_dimension(0)
|
| | | {
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Destructor. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 22:59:48 +03:00 | | | void CD2SkillItem::~CD2SkillItem(void)
|
2026-08-20 19:55:53 +03:00 | | | {
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Initializes the item and allocates its GPU-resident correction, |
|
| | | //| direction, scale, observation and mass buffers. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | bool CD2SkillItem::Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl,
|
| | | uint numNeurons, ENUM_OPTIMIZATION optimization_type,
|
| | | uint batch)
|
| | | {
|
| | | m_correction = NULL;
|
| | | m_item_dimension = numNeurons;
|
| | | if(!CNeuronBaseOCL::Init(numOutputs, myIndex, open_cl, numNeurons,
|
| | | optimization_type, batch))
|
| | | ReturnFalse;
|
| | | return(EnsureItemState());
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Attaches the external correction buffer when its layout matches |
|
| | | //| the item output. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | bool CD2SkillItem::SetCorrectionBuffer(CBufferFloat *correction)
|
| | | {
|
| | | if(!correction || CheckPointer(correction) == POINTER_INVALID)
|
2026-08-18 19:58:41 +03:00 | | | {
|
2026-08-20 19:55:53 +03:00 | | | m_correction = NULL;
|
2026-08-18 19:58:41 +03:00 | | | return(true);
|
| | | }
|
2026-08-20 19:55:53 +03:00 | | | if(!Output || correction.Total() != Output.Total() ||
|
| | | correction.GetOpenCL() != OpenCL)
|
| | | ReturnFalse;
|
| | | m_correction = correction;
|
| | | return(true);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns the attached correction buffer. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | CBufferFloat *CD2SkillItem::GetCorrectionBuffer(void) const
|
| | | {
|
| | | return(m_correction);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Sets the representation mode of the item. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | void CD2SkillItem::SetRepresentation(const ED2SkillRepresentation mode)
|
| | | {
|
| | | m_representation = mode;
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns the current representation mode. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | ED2SkillRepresentation CD2SkillItem::Representation(void) const
|
| | | {
|
| | | return(m_representation);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Sets the EMA smoothing factors for correction, direction and |
|
| | | //| magnitude, clamped to [0,1]. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | void CD2SkillItem::SetEMA(const float beta_correction, const float beta_direction,
|
| | | const float beta_magnitude)
|
| | | {
|
| | | m_beta_correction = MathMin(MathMax(beta_correction, 0.0f), 1.0f);
|
| | | m_beta_direction = MathMin(MathMax(beta_direction, 0.0f), 1.0f);
|
| | | m_beta_magnitude = MathMin(MathMax(beta_magnitude, 0.0f), 1.0f);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns the correction EMA smoothing factor. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | float CD2SkillItem::BetaCorrection(void) const
|
| | | {
|
| | | return(m_beta_correction);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns the direction EMA smoothing factor. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | float CD2SkillItem::BetaDirection(void) const
|
| | | {
|
| | | return(m_beta_direction);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns the magnitude EMA smoothing factor. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | float CD2SkillItem::BetaMagnitude(void) const
|
| | | {
|
| | | return(m_beta_magnitude);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns the item correction buffer pointer. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | CBufferFloat *CD2SkillItem::Correction(void)
|
| | | {
|
| | | return(m_correction);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns the item direction buffer. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | CBufferFloat *CD2SkillItem::Direction(void)
|
| | | {
|
| | | return(GetPointer(m_item_direction));
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns the item scale buffer. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | CBufferFloat *CD2SkillItem::Scale(void)
|
| | | {
|
| | | return(GetPointer(m_item_scale));
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns the item observation counter buffer. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | CBufferFloat *CD2SkillItem::Observations(void)
|
| | | {
|
| | | return(GetPointer(m_item_observations));
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns the item mass buffer. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | CBufferFloat *CD2SkillItem::Mass(void)
|
| | | {
|
| | | return(GetPointer(m_item_mass));
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| No-op: a skill item exposes no trainable weights. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | bool CD2SkillItem::updateInputWeights(CNeuronBaseOCL *NeuronOCL)
|
| | | {
|
| | | return(true);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns the item neuron type identifier (defNeuronD2SkillItem). |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | int CD2SkillItem::Type(void) const
|
| | | {
|
| | | return(defNeuronD2SkillItem);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Rebinds a bank GPU buffer to the given OpenCL object. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | void CD2SkillBank::RebindBuffer(CBufferFloat &buffer, COpenCLMy *obj)
|
| | | {
|
| | | if(!obj)
|
| | | return;
|
| | | if(buffer.GetOpenCL() != NULL && buffer.GetIndex() >= 0)
|
| | | buffer.BufferFree();
|
| | | buffer.BufferCreate(obj);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Checks that every bank buffer matches the required |
|
| | | //| slot-by-dimension layout. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | bool CD2SkillBank::ValidateBuffers(void)
|
| | | {
|
| | | const long total = (long)m_slots * (long)m_dimension;
|
| | | if(total <= 0 || total > 2147483647 ||
|
| | | !Output || !Gradient || Output.Total() != (int)m_dimension ||
|
| | | Gradient.Total() != (int)m_dimension)
|
| | | ReturnFalse;
|
| | | return(m_keys.Total() == (int)total &&
|
| | | m_corrections.Total() == (int)total &&
|
| | | m_directions.Total() == (int)total &&
|
| | | m_scales.Total() == (int)m_slots &&
|
| | | m_utility.Total() == (int)m_slots &&
|
| | | m_observations.Total() == (int)m_slots &&
|
| | | m_uses.Total() == (int)m_slots &&
|
| | | m_mass.Total() == (int)m_slots &&
|
| | | m_used.Total() == (int)m_slots &&
|
| | | m_state.Total() == (int)m_slots &&
|
| | | m_age.Total() == (int)m_slots &&
|
| | | m_protection.Total() == (int)m_slots &&
|
| | | m_influence.Total() == (int)m_slots &&
|
2026-08-27 11:39:46 +03:00 | | | m_utility_applied.Total() == (int)m_slots &&
|
2026-08-20 22:59:48 +03:00 | | | m_gradient_influence_total.Total() == 1 &&
|
2026-08-20 19:55:53 +03:00 | | | m_retrieved.Total() == (int)m_slots &&
|
| | | m_selected_correction.Total() == (int)m_dimension &&
|
| | | m_selected_slot.Total() == 1 &&
|
| | | m_selected_score.Total() == 1 &&
|
| | | m_diagnostics.Total() == D2SKILL_DIAGNOSTICS &&
|
| | | m_utility_distribution.Total() == D2SKILL_DISTRIBUTION_BINS &&
|
| | | m_usage_distribution.Total() == D2SKILL_DISTRIBUTION_BINS);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Initializes a bank GPU buffer with the given total and fill |
|
| | | //| value. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | bool CD2SkillBank::InitBuffer(CBufferFloat &buffer, const int total, const float value)
|
| | | {
|
| | | return(buffer.BufferInit(total, value) && buffer.BufferCreate(OpenCL));
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Constructor: initializes thresholds, EMAs, lifecycle and policy |
|
| | | //| defaults. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | CD2SkillBank::CD2SkillBank(void) : m_slots(0), m_dimension(0), m_enabled(false),
|
| | | m_similarity_threshold(0.65f), m_direction_threshold(0.0f),
|
| | | m_utility_weight(0.05f), m_beta_key(0.05f),
|
| | | m_beta_utility(0.05f), m_alpha(1.0f),
|
| | | m_min_utility(-1.0f), m_utility_aware(false),
|
| | | m_max_correction(10.0f), m_min_confirmations(3),
|
| | | m_protection_age(32), m_inactivity_age(256),
|
| | | m_active_slot(UINT_MAX)
|
| | | {
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Destructor. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | CD2SkillBank::~CD2SkillBank(void)
|
| | | {
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns the bank neuron type identifier (defNeuronD2SkillBank). |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | int CD2SkillBank::Type(void) const
|
| | | {
|
| | | return(defNeuronD2SkillBank);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Enables or disables the bank. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | bool CD2SkillBank::SetEnabled(const bool enabled)
|
| | | {
|
| | | m_enabled = enabled;
|
| | | return(true);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns whether the bank is enabled. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | bool CD2SkillBank::Enabled(void) const
|
| | | {
|
| | | return(m_enabled);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Sets the similarity and direction thresholds used for slot |
|
| | | //| scoring. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | bool CD2SkillBank::SetThresholds(const float similarity, const float direction)
|
| | | {
|
| | | if(!MathIsValidNumber(similarity) || !MathIsValidNumber(direction))
|
| | | ReturnFalse;
|
| | | m_similarity_threshold = similarity;
|
| | | m_direction_threshold = direction;
|
| | | return(true);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Sets the utility weighting applied when scoring slots. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | bool CD2SkillBank::SetUtilityWeight(const float value)
|
| | | {
|
| | | if(!MathIsValidNumber(value))
|
| | | ReturnFalse;
|
| | | m_utility_weight = value;
|
| | | return(true);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Sets the residual blend factor alpha, clamped to [0,1]. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | bool CD2SkillBank::SetAlpha(const float value)
|
| | | {
|
| | | if(!MathIsValidNumber(value) || value < 0.0f || value > 1.0f)
|
| | | ReturnFalse;
|
| | | m_alpha = value;
|
| | | return(true);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns the residual blend factor alpha. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | float CD2SkillBank::Alpha(void) const
|
| | | {
|
| | | return(m_alpha);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Enables utility-aware slot scoring and sets the minimum utility. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | bool CD2SkillBank::SetUtilityPolicy(const bool utility_aware, const float min_utility)
|
| | | {
|
| | | if(!MathIsValidNumber(min_utility) || min_utility < -1.0f || min_utility > 1.0f)
|
| | | ReturnFalse;
|
| | | m_utility_aware = utility_aware;
|
| | | m_min_utility = min_utility;
|
| | | return(true);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns whether utility-aware scoring is enabled. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | bool CD2SkillBank::UtilityAware(void) const
|
| | | {
|
| | | return(m_utility_aware);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns the minimum utility required for slot selection. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | float CD2SkillBank::MinUtility(void) const
|
| | | {
|
| | | return(m_min_utility);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Sets the confirmation, protection and inactivity ages of the slot|
|
| | | //| lifecycle. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | bool CD2SkillBank::SetLifecycle(const uint confirmations, const uint protection_age,
|
| | | const uint inactivity_age)
|
| | | {
|
| | | if(confirmations == 0)
|
| | | ReturnFalse;
|
| | | m_min_confirmations = confirmations;
|
| | | m_protection_age = protection_age;
|
| | | m_inactivity_age = MathMax(inactivity_age, protection_age + 1);
|
| | | return(true);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Sets the maximum magnitude allowed for a slot correction. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | bool CD2SkillBank::SetMaxCorrection(const float value)
|
| | | {
|
| | | if(!MathIsValidNumber(value) || value < 0.0f)
|
| | | ReturnFalse;
|
| | | m_max_correction = value;
|
| | | return(true);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns the maximum allowed correction magnitude. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | float CD2SkillBank::MaxCorrection(void) const
|
| | | {
|
| | | return(m_max_correction);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns the number of slots in the bank. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | uint CD2SkillBank::Slots(void) const
|
| | | {
|
| | | return(m_slots);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns the dimension of each slot vector. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | uint CD2SkillBank::Dimension(void) const
|
| | | {
|
| | | return(m_dimension);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns the currently selected slot index (UINT_MAX when none). |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | uint CD2SkillBank::ActiveSlot(void) const
|
| | | {
|
| | | return(m_active_slot);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns the buffer holding the selected slot correction. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | CBufferFloat *CD2SkillBank::SelectedCorrection(void) { return(GetPointer(m_selected_correction)); }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns the buffer holding the selected slot index. |
|
2026-08-20 19:55:53 +03:00 | | | //+------------------------------------------------------------------+
|
| | | CBufferFloat *CD2SkillBank::SelectedSlot(void) { return(GetPointer(m_selected_slot)); }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns the buffer holding the selected slot score. |
|
2026-08-20 19:55:53 +03:00 | | | //+------------------------------------------------------------------+
|
| | | CBufferFloat *CD2SkillBank::SelectedScore(void) { return(GetPointer(m_selected_score)); }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns the slot key buffer. |
|
2026-08-20 19:55:53 +03:00 | | | //+------------------------------------------------------------------+
|
| | | CBufferFloat *CD2SkillBank::Keys(void) { return(GetPointer(m_keys)); }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns the per-slot correction buffer. |
|
2026-08-20 19:55:53 +03:00 | | | //+------------------------------------------------------------------+
|
| | | CBufferFloat *CD2SkillBank::Corrections(void) { return(GetPointer(m_corrections)); }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns the per-slot direction buffer. |
|
2026-08-20 19:55:53 +03:00 | | | //+------------------------------------------------------------------+
|
| | | CBufferFloat *CD2SkillBank::Directions(void) { return(GetPointer(m_directions)); }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns the per-slot scale buffer. |
|
2026-08-20 19:55:53 +03:00 | | | //+------------------------------------------------------------------+
|
| | | CBufferFloat *CD2SkillBank::Scales(void) { return(GetPointer(m_scales)); }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns the per-slot observation counter buffer. |
|
2026-08-20 19:55:53 +03:00 | | | //+------------------------------------------------------------------+
|
| | | CBufferFloat *CD2SkillBank::ObservationsBank(void) { return(GetPointer(m_observations)); }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns the per-slot use counter buffer. |
|
2026-08-20 19:55:53 +03:00 | | | //+------------------------------------------------------------------+
|
| | | CBufferFloat *CD2SkillBank::Uses(void) { return(GetPointer(m_uses)); }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns the per-slot mass buffer. |
|
2026-08-20 19:55:53 +03:00 | | | //+------------------------------------------------------------------+
|
| | | CBufferFloat *CD2SkillBank::MassBank(void) { return(GetPointer(m_mass)); }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns the per-slot utility buffer. |
|
2026-08-20 19:55:53 +03:00 | | | //+------------------------------------------------------------------+
|
| | | CBufferFloat *CD2SkillBank::Utility(void) { return(GetPointer(m_utility)); }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns the per-slot used flag buffer. |
|
2026-08-20 19:55:53 +03:00 | | | //+------------------------------------------------------------------+
|
| | | CBufferFloat *CD2SkillBank::Used(void) { return(GetPointer(m_used)); }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns the per-slot state buffer. |
|
2026-08-20 19:55:53 +03:00 | | | //+------------------------------------------------------------------+
|
| | | CBufferFloat *CD2SkillBank::State(void) { return(GetPointer(m_state)); }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns the per-slot age buffer. |
|
2026-08-20 19:55:53 +03:00 | | | //+------------------------------------------------------------------+
|
| | | CBufferFloat *CD2SkillBank::Ages(void) { return(GetPointer(m_age)); }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns the per-slot protection counter buffer. |
|
2026-08-20 19:55:53 +03:00 | | | //+------------------------------------------------------------------+
|
| | | CBufferFloat *CD2SkillBank::Protection(void) { return(GetPointer(m_protection)); }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns the bank diagnostics buffer. |
|
2026-08-20 19:55:53 +03:00 | | | //+------------------------------------------------------------------+
|
| | | CBufferFloat *CD2SkillBank::Diagnostics(void) { return(GetPointer(m_diagnostics)); }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns the utility distribution histogram buffer. |
|
2026-08-20 19:55:53 +03:00 | | | //+------------------------------------------------------------------+
|
| | | CBufferFloat *CD2SkillBank::UtilityDistribution(void) { return(GetPointer(m_utility_distribution)); }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns the usage distribution histogram buffer. |
|
2026-08-20 19:55:53 +03:00 | | | //+------------------------------------------------------------------+
|
| | | CBufferFloat *CD2SkillBank::UsageDistribution(void) { return(GetPointer(m_usage_distribution)); }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns the per-slot influence buffer. |
|
2026-08-20 19:55:53 +03:00 | | | //+------------------------------------------------------------------+
|
| | | CBufferFloat *CD2SkillBank::Influence(void) { return(GetPointer(m_influence)); }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns the per-slot retrieved flag buffer. |
|
2026-08-20 19:55:53 +03:00 | | | //+------------------------------------------------------------------+
|
| | | CBufferFloat *CD2SkillBank::Retrieved(void) { return(GetPointer(m_retrieved)); }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Constructor: starts unmaterialized with both banks disabled. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-26 18:00:29 +03:00 | | | CD2Skill::CD2Skill(void) : m_ready(false), m_task_bank_materialized(false),
|
| | | m_step_bank_materialized(false), m_online_direction_update(false), m_mode(D2_DISABLED)
|
2026-08-20 19:55:53 +03:00 | | | {
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Destructor. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | CD2Skill::~CD2Skill(void)
|
| | | {
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns the skill neuron type identifier (defNeuronD2Skill). |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | int CD2Skill::Type(void) const
|
| | | {
|
| | | return(defNeuronD2Skill);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns the current skill runtime mode. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | ENUM_D2SKILL_MODE CD2Skill::Mode(void) const
|
| | | {
|
| | | return(m_mode);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns whether the skill is ready after a successful |
|
| | | //| initialization. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | bool CD2Skill::Ready(void) const
|
| | | {
|
| | | return(m_ready);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns the Task bank pointer when ready, otherwise NULL. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | CD2SkillBank *CD2Skill::TaskBank(void)
|
| | | {
|
| | | return(m_ready ? GetPointer(m_task_bank) : NULL);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns the Step bank pointer when ready, otherwise NULL. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | CD2SkillBank *CD2Skill::StepBank(void)
|
| | | {
|
| | | return(m_ready ? GetPointer(m_step_bank) : NULL);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns the primary (Task) bank pointer when ready, otherwise |
|
| | | //| NULL. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | CD2SkillBank *CD2Skill::Bank(void)
|
| | | {
|
| | | return(TaskBank());
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns the primary (Task) bank pointer (const) when ready, |
|
| | | //| otherwise NULL. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | const CD2SkillBank *CD2Skill::Bank(void) const
|
| | | {
|
| | | return(TaskBank());
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns the Task bank pointer (const) when ready, otherwise NULL.|
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | const CD2SkillBank *CD2Skill::TaskBank(void) const
|
| | | {
|
| | | return(m_ready ? GetPointer(m_task_bank) : NULL);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns the Step bank pointer (const) when ready, otherwise NULL.|
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | const CD2SkillBank *CD2Skill::StepBank(void) const
|
| | | {
|
| | | return(m_ready ? GetPointer(m_step_bank) : NULL);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-14 09:56:18 +03:00 | | | //| Checks D2 composition readiness, including deferred banks. |
|
| | | //+------------------------------------------------------------------+
|
| | | bool CD2Skill::SupportsOpenCLChecked(void) const
|
| | | {
|
| | | //--- Validate the exact D2 identity and complete Scenario-owned tree.
|
| | | if(Type() != defNeuronD2Skill || !m_ready || bCritic ||
|
| | | !ValidateScenarioOwnedTreeChecked())
|
| | | return(false);
|
| | |
|
| | | //--- Validate each Bank using its current materialization state.
|
| | | if(m_task_bank_materialized && !m_task_bank.SupportsOpenCLChecked())
|
| | | return(false);
|
| | | if(!m_task_bank_materialized && !m_task_bank.SupportsDeferredOpenCLChecked())
|
| | | return(false);
|
| | | if(m_step_bank_materialized && !m_step_bank.SupportsOpenCLChecked())
|
| | | return(false);
|
| | | if(!m_step_bank_materialized && !m_step_bank.SupportsDeferredOpenCLChecked())
|
| | | return(false);
|
| | |
|
| | | //--- Bound tensor products before comparing derived dimensions.
|
| | | const long max_elements = INT_MAX;
|
| | | if((long)iQueries > max_elements / (long)iScenarios ||
|
| | | (long)iQueries * (long)iScenarios > max_elements / (long)iDimension ||
|
| | | (long)iScenarios > max_elements / (long)iVariables ||
|
| | | (long)iScenarios * (long)iVariables > max_elements / (long)iHorizon ||
|
| | | (long)iScenarios * (long)iVariables * (long)iHorizon > max_elements / (long)iDimension)
|
| | | return(false);
|
| | |
|
| | | //--- Confirm the established Task and Step dimensions and slot counts.
|
| | | return(m_task_bank.Dimension() == (uint)((long)iQueries * iScenarios * iDimension) &&
|
| | | m_task_bank.Slots() == iScenarios &&
|
| | | m_step_bank.Dimension() == (uint)((long)iScenarios * iVariables * iHorizon * iDimension) &&
|
| | | m_step_bank.Slots() == iScenarios);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
| | | //| Transfers both banks before publishing the Scenario parent. |
|
| | | //+------------------------------------------------------------------+
|
| | | bool CD2Skill::SetOpenCLChecked(COpenCLMy *obj)
|
| | | {
|
| | | //--- Validate the exact model and both Bank states before either Bank is prepared.
|
| | | if(CheckPointer(obj) == POINTER_INVALID || !SupportsOpenCLChecked())
|
| | | ReturnFalseEx("checked target or capability");
|
| | | if(m_task_bank_materialized && !m_task_bank.SupportsOpenCLChecked(obj))
|
| | | ReturnFalseEx("checked Task prevalidation");
|
| | | if(!m_task_bank_materialized && !m_task_bank.SupportsDeferredOpenCLChecked(obj))
|
| | | ReturnFalseEx("checked Task prevalidation");
|
| | | if(m_step_bank_materialized && !m_step_bank.SupportsOpenCLChecked(obj))
|
| | | ReturnFalseEx("checked Step prevalidation");
|
| | | if(!m_step_bank_materialized && !m_step_bank.SupportsDeferredOpenCLChecked(obj))
|
| | | ReturnFalseEx("checked Step prevalidation");
|
| | |
|
| | | //--- Prepare and transfer Task before publishing its readiness.
|
| | | if(!m_task_bank_materialized && !m_task_bank.PrepareOpenCLChecked(obj))
|
| | | ReturnFalseEx("checked Task prepare");
|
| | | if(!m_task_bank.SetOpenCLChecked(obj))
|
| | | ReturnFalseEx("checked Task context");
|
| | | if(!m_task_bank_materialized)
|
| | | m_task_bank_materialized = true;
|
| | |
|
| | | //--- Prepare and transfer Step before publishing its readiness.
|
| | | if(!m_step_bank_materialized && !m_step_bank.PrepareOpenCLChecked(obj))
|
| | | ReturnFalseEx("checked Step prepare");
|
| | | if(!m_step_bank.SetOpenCLChecked(obj))
|
| | | ReturnFalseEx("checked Step context");
|
| | | if(!m_step_bank_materialized)
|
| | | m_step_bank_materialized = true;
|
| | |
|
| | | //--- Publish the Scenario parent only after both Bank transfers succeed.
|
| | | if(!CNeuronScenarioCrossAttention::SetOpenCLChecked(obj))
|
| | | ReturnFalseEx("checked Scenario context");
|
| | | return(true);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
| | | //| Enables the Task and/or Step branch after checked preparation. |
|
2026-09-04 17:39:51 +03:00 | | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | bool CD2Skill::Enable(const bool task, const bool step)
|
| | | {
|
2026-09-14 09:56:18 +03:00 | | | //--- Validate every requested Bank before preparing either deferred branch.
|
2026-08-26 18:00:29 +03:00 | | | if(!m_ready || !OpenCL)
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-09-14 09:56:18 +03:00 | | | if(task && m_task_bank_materialized && !m_task_bank.SupportsOpenCLChecked(OpenCL))
|
| | | ReturnFalse;
|
| | | if(task && !m_task_bank_materialized && !m_task_bank.SupportsDeferredOpenCLChecked(OpenCL))
|
| | | ReturnFalse;
|
| | | if(step && m_step_bank_materialized && !m_step_bank.SupportsOpenCLChecked(OpenCL))
|
| | | ReturnFalse;
|
| | | if(step && !m_step_bank_materialized && !m_step_bank.SupportsDeferredOpenCLChecked(OpenCL))
|
| | | ReturnFalse;
|
| | |
|
| | | //--- Prepare and transfer requested deferred Banks without changing enabled state.
|
2026-08-26 18:00:29 +03:00 | | | if(task && !m_task_bank_materialized)
|
| | | {
|
2026-09-14 09:56:18 +03:00 | | | if(!m_task_bank.PrepareOpenCLChecked(OpenCL))
|
| | | ReturnFalse;
|
| | | if(!m_task_bank.SetOpenCLChecked(OpenCL))
|
| | | ReturnFalse;
|
| | | if(!m_task_bank.SetCorrectionBuffer(m_task_bank.SelectedCorrection()))
|
| | | ReturnFalse;
|
2026-08-26 18:00:29 +03:00 | | | m_task_bank_materialized = true;
|
| | | }
|
| | | if(step && !m_step_bank_materialized)
|
| | | {
|
2026-09-14 09:56:18 +03:00 | | | if(!m_step_bank.PrepareOpenCLChecked(OpenCL))
|
| | | ReturnFalse;
|
| | | if(!m_step_bank.SetOpenCLChecked(OpenCL))
|
| | | ReturnFalse;
|
| | | if(!m_step_bank.SetCorrectionBuffer(m_step_bank.SelectedCorrection()))
|
| | | ReturnFalse;
|
2026-08-26 18:00:29 +03:00 | | | m_step_bank_materialized = true;
|
| | | }
|
2026-09-14 09:56:18 +03:00 | | | //--- Bind selected correction aliases only after all requested transfers succeed.
|
| | | if(task && m_task_bank.GetCorrectionBuffer() == NULL &&
|
| | | !m_task_bank.SetCorrectionBuffer(m_task_bank.SelectedCorrection()))
|
| | | ReturnFalse;
|
| | | if(step && m_step_bank.GetCorrectionBuffer() == NULL &&
|
| | | !m_step_bank.SetCorrectionBuffer(m_step_bank.SelectedCorrection()))
|
| | | ReturnFalse;
|
2026-08-20 19:55:53 +03:00 | | | m_task_bank.SetEnabled(task);
|
| | | m_step_bank.SetEnabled(step);
|
| | | return(true);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Runs the Task bank feed-forward on the given source. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | bool CD2Skill::TaskFeedForward(CNeuronBaseOCL *source)
|
| | | {
|
| | | return(m_ready && m_task_bank.FeedForward(source));
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Runs the Step bank feed-forward on the given source. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | bool CD2Skill::StepFeedForward(CNeuronBaseOCL *source)
|
| | | {
|
| | | return(m_ready && m_step_bank.FeedForward(source));
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Applies the pseudo-residual update to the Task bank. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | bool CD2Skill::TaskUpdate(CBufferFloat *state, CBufferFloat *gradient)
|
| | | {
|
| | | return(m_ready && m_task_bank.UpdateFromGradient(state, gradient));
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Applies the pseudo-residual update to the Step bank. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | bool CD2Skill::StepUpdate(CBufferFloat *state, CBufferFloat *gradient)
|
| | | {
|
| | | return(m_ready && m_step_bank.UpdateFromGradient(state, gradient));
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Applies the utility update to the Task bank; reports whether it |
|
| | | //| was applied. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-27 11:39:46 +03:00 | | | bool CD2Skill::TaskUtility(const float delta_j, bool &applied)
|
2026-08-20 19:55:53 +03:00 | | | {
|
2026-08-27 11:39:46 +03:00 | | | applied = false;
|
2026-08-20 22:59:48 +03:00 | | | if(!m_ready || (m_mode != D2_EVALUATE && m_mode != D2_ONLINE_CALIBRATION))
|
| | | ReturnFalse;
|
2026-08-27 11:39:46 +03:00 | | | return(m_task_bank.UpdateUtility(delta_j, applied));
|
2026-08-20 19:55:53 +03:00 | | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Applies the utility update to the Task bank. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-27 11:39:46 +03:00 | | | bool CD2Skill::TaskUtility(const float delta_j)
|
| | | {
|
| | | bool applied = false;
|
| | | return(TaskUtility(delta_j, applied));
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Applies the utility update to the Step bank; reports whether it |
|
| | | //| was applied. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-27 11:39:46 +03:00 | | | bool CD2Skill::StepUtility(const float delta_j, bool &applied)
|
2026-08-20 19:55:53 +03:00 | | | {
|
2026-08-27 11:39:46 +03:00 | | | applied = false;
|
2026-08-20 22:59:48 +03:00 | | | if(!m_ready || (m_mode != D2_EVALUATE && m_mode != D2_ONLINE_CALIBRATION))
|
| | | ReturnFalse;
|
2026-08-27 11:39:46 +03:00 | | | return(m_step_bank.UpdateUtility(delta_j, applied));
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Applies the utility update to the Step bank. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-27 11:39:46 +03:00 | | | bool CD2Skill::StepUtility(const float delta_j)
|
| | | {
|
| | | bool applied = false;
|
| | | return(StepUtility(delta_j, applied));
|
2026-08-20 19:55:53 +03:00 | | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Runs the second-pass backward propagation through the skill |
|
| | | //| highway. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | bool CD2Skill::BackwardSecond(CNeuronBaseOCL *source, CNeuronBaseOCL *forecast)
|
| | | {
|
| | | return(m_ready && calcInputGradientsSecond(source, forecast));
|
| | | }
|
2026-08-18 19:58:41 +03:00 | | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Initializes the skill, its scenario-attention base and both |
|
| | | //| Task/Step banks. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-18 19:58:41 +03:00 | | | bool CD2Skill::Init(uint numOutputs, uint myIndex, COpenCLMy *opencl,
|
| | | uint scenarios, uint horizon, uint latent, bool critic,
|
| | | ENUM_OPTIMIZATION optimization_type, uint batch,
|
| | | uint variables, uint stack_size, uint top_k)
|
| | | {
|
| | | if(critic)
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | m_ready = false;
|
2026-08-20 19:55:53 +03:00 | | | m_mode = D2_DISABLED;
|
2026-08-18 19:58:41 +03:00 | | | if(!CNeuronScenarioCrossAttention::Init(numOutputs, myIndex, opencl,
|
| | | scenarios, horizon, latent, false,
|
| | | optimization_type, batch, variables,
|
| | | stack_size, top_k))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | if(!InitBanks(optimization_type, batch))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-26 18:00:29 +03:00 | | | m_task_bank_materialized = true;
|
| | | m_step_bank_materialized = true;
|
2026-08-18 19:58:41 +03:00 | | | m_task_bank.SetEnabled(false);
|
| | | m_step_bank.SetEnabled(false);
|
| | | m_ready = true;
|
| | | return(true);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Creates the Task and Step banks with dimensions derived from the |
|
| | | //| attention layout. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-18 19:58:41 +03:00 | | | bool CD2Skill::InitBanks(ENUM_OPTIMIZATION optimization_type, uint batch)
|
| | | {
|
| | | const uint task_dimension = iQueries * iScenarios * iDimension;
|
| | | const uint step_dimension = iScenarios * iVariables * iHorizon * iDimension;
|
| | | if(task_dimension == 0 || step_dimension == 0 || !OpenCL)
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | if(!m_task_bank.Init(task_dimension, 100000, OpenCL, iScenarios,
|
| | | optimization_type, batch))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | if(!m_step_bank.Init(step_dimension, 100001, OpenCL, iScenarios,
|
| | | optimization_type, batch))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | m_task_bank.SetActivationFunction(None);
|
| | | m_step_bank.SetActivationFunction(None);
|
| | | return(true);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns whether the Task branch is active in the current runtime |
|
| | | //| mode. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | bool CD2Skill::TaskSkillEnabled(void) const
|
2026-08-18 19:58:41 +03:00 | | | {
|
2026-08-20 22:59:48 +03:00 | | | return(m_ready && m_task_bank.Enabled() &&
|
| | | (m_mode == D2_EVALUATE || m_mode == D2_INFERENCE ||
|
| | | m_mode == D2_ONLINE_CALIBRATION));
|
2026-08-18 19:58:41 +03:00 | | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns whether the Step branch is active in the current runtime |
|
| | | //| mode. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | bool CD2Skill::StepSkillEnabled(void) const
|
2026-08-18 19:58:41 +03:00 | | | {
|
2026-08-20 22:59:48 +03:00 | | | return(m_ready && m_step_bank.Enabled() &&
|
| | | (m_mode == D2_EVALUATE || m_mode == D2_INFERENCE ||
|
| | | m_mode == D2_ONLINE_CALIBRATION));
|
2026-08-18 19:58:41 +03:00 | | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Returns whether bank weights are writable (D2_COLLECT mode only).|
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | bool CD2Skill::SkillUpdatesEnabled(void) const
|
2026-08-18 19:58:41 +03:00 | | | {
|
2026-08-20 22:59:48 +03:00 | | | return(m_mode == D2_COLLECT);
|
2026-08-18 19:58:41 +03:00 | | | }
|
| | | //+------------------------------------------------------------------+
|
2026-08-21 08:18:10 +03:00 | | | //| Enables only the opt-in online direction EMA. |
|
| | | //+------------------------------------------------------------------+
|
| | | bool CD2Skill::OnlineDirectionUpdatesEnabled(void) const
|
| | | {
|
| | | return(m_mode == D2_ONLINE_CALIBRATION && m_online_direction_update);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
| | | //| Updates one selected bank direction without mutating its lifecycle. |
|
| | | //+------------------------------------------------------------------+
|
| | | bool CD2Skill::UpdateOnlineDirection(CD2SkillBank *bank, CBufferFloat *gradient)
|
| | | {
|
| | | if(!OnlineDirectionUpdatesEnabled() || !bank || !bank.Enabled())
|
| | | return(true);
|
| | | if(!gradient)
|
| | | ReturnFalse;
|
| | | return(bank.UpdateDirectionFromGradient(gradient));
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Runs the second-pass feed-forward: optional banks, token |
|
| | | //| attention and history gates. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | bool CD2Skill::feedForwardSecond(CNeuronBaseOCL *NeuronOCL,
|
| | | CNeuronBaseOCL *Forecast)
|
2026-08-18 19:58:41 +03:00 | | | {
|
2026-08-20 19:55:53 +03:00 | | | if(!OpenCL || !NeuronOCL || !Forecast || Forecast.Type() != defNeuronScenarioForecast ||
|
| | | NeuronOCL.Neurons() != int(bCritic ? 19 : 13))
|
| | | ReturnFalse;
|
| | | CNeuronScenarioForecast *forecast = Forecast;
|
| | | if(forecast.Variables() != iVariables || forecast.Scenarios() != iScenarios ||
|
| | | forecast.Horizon() != iHorizon || forecast.Dimension() != iDimension ||
|
| | | Forecast.Neurons() != int(iScenarios * iVariables * iHorizon * iDimension) ||
|
| | | !forecast.GetLogU() || forecast.GetLogU().Total() != int(iScenarios * iVariables * iHorizon) ||
|
| | | !forecast.GetPi() || forecast.GetPi().Total() != int(iScenarios))
|
| | | ReturnFalse;
|
| | | if(!cQueryProjection.FeedForward(NeuronOCL))
|
| | | ReturnFalse;
|
| | | CNeuronBaseOCL *task_source = cQueryProjection.AsObject();
|
| | | if(TaskSkillEnabled())
|
| | | {
|
| | | if(!m_task_bank.FeedForward(task_source))
|
| | | ReturnFalse;
|
| | | task_source = m_task_bank.AsObject();
|
| | | }
|
2026-08-21 08:18:10 +03:00 | | | else
|
| | | if(m_mode == D2_COLLECT && m_task_bank.Enabled() &&
|
| | | !m_task_bank.Observe(task_source))
|
| | | ReturnFalse;
|
2026-08-20 19:55:53 +03:00 | | | if(!cWz.FeedForward(Forecast))
|
| | | ReturnFalse;
|
2026-08-20 22:59:48 +03:00 | | | CNeuronBaseOCL *step_source = cWz.AsObject();
|
2026-08-20 19:55:53 +03:00 | | | if(StepSkillEnabled())
|
| | | {
|
| | | if(!m_step_bank.FeedForward(step_source))
|
| | | ReturnFalse;
|
| | | step_source = m_step_bank.AsObject();
|
| | | }
|
2026-08-21 08:18:10 +03:00 | | | else
|
| | | if(m_mode == D2_COLLECT && m_step_bank.Enabled() &&
|
| | | !m_step_bank.Observe(step_source))
|
| | | ReturnFalse;
|
2026-08-20 22:59:48 +03:00 | | | if(!cWu.FeedForwardBuffer(forecast.GetLogU()))
|
| | | ReturnFalse;
|
| | | if(!SumAndNormalize(step_source.getOutput(), cWu.getOutput(), cTokenSum.getOutput(),
|
| | | 1, false, 0, 0, 0, 1))
|
| | | ReturnFalse;
|
| | | if(!cTokenPE.FeedForward(cTokenSum.AsObject()))
|
| | | ReturnFalse;
|
| | | if(!cTokensTranspose.FeedForward(cTokenPE.AsObject()))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
| | | if(!Concat(cTokensTranspose.getOutput(), cTokensTranspose.getOutput(), cKV.getOutput(),
|
| | | iScenarios * iDimension, iScenarios * iDimension, iVariables * iHorizon))
|
| | | ReturnFalse;
|
| | | if(!cAttention.FeedForward(task_source, cKV.getOutput()))
|
| | | ReturnFalse;
|
| | | if(!cAttentionTranspose.FeedForward(cAttention.AsObject()))
|
| | | ReturnFalse;
|
| | | if(!bCritic)
|
| | | {
|
| | | if(!cHistoryStack.FeedForward(GetPointer(this)))
|
| | | ReturnFalse;
|
| | | if(!cHistoryTTM.FeedForward(cAttentionTranspose.AsObject(), cHistoryStack.getOutput()))
|
| | | ReturnFalse;
|
| | | if(!cHistoryTokenProjection.FeedForward(cTokenPE.AsObject()))
|
| | | ReturnFalse;
|
| | | if(!cHistoryMarket.FeedForward(cHistoryStack.AsObject(), cHistoryTokenProjection.getOutput()))
|
| | | ReturnFalse;
|
| | | if(!cHistoryContext.FeedForward(cHistoryTTM.AsObject(), cHistoryMarket.getOutput()))
|
| | | ReturnFalse;
|
| | | if(!cScenarioHistory.FeedForward(cAttentionTranspose.AsObject(), cHistoryContext.getOutput()))
|
| | | ReturnFalse;
|
| | | if(!ScalarToVector(forecast.GetPi(), cScenarioHistory.getOutput(), cHeadGate.getOutput(),
|
| | | iQueries * iDimension))
|
| | | ReturnFalse;
|
| | | }
|
| | | else
|
| | | if(!ScalarToVector(forecast.GetPi(), cAttentionTranspose.getOutput(), cHeadGate.getOutput(),
|
| | | iQueries * iDimension))
|
| | | ReturnFalse;
|
| | | if(!cHeadGateTranspose.FeedForward(cHeadGate.AsObject()))
|
| | | ReturnFalse;
|
| | | if(!cOutputProjection.FeedForward(cHeadGateTranspose.AsObject()))
|
| | | ReturnFalse;
|
| | | if(!cQueryResidual.FeedForward(task_source))
|
| | | ReturnFalse;
|
| | | if(!SumAndNormalize(cOutputProjection.getOutput(), cQueryResidual.getOutput(), cMHAOutput.getOutput(),
|
| | | 1, true, 0, 0, 0, 1))
|
| | | ReturnFalse;
|
| | | return(CNeuronMSRes::feedForward(cMHAOutput.AsObject()));
|
2026-08-18 19:58:41 +03:00 | | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Back-propagates the second-pass gradients, including bank |
|
| | | //| influence accumulation. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | bool CD2Skill::calcInputGradientsSecond(CNeuronBaseOCL *NeuronOCL,
|
| | | CNeuronBaseOCL *Forecast)
|
2026-08-18 19:58:41 +03:00 | | | {
|
2026-08-20 19:55:53 +03:00 | | | if(!OpenCL || !NeuronOCL || !Forecast || Forecast.Type() != defNeuronScenarioForecast)
|
| | | ReturnFalse;
|
| | | CNeuronScenarioForecast *forecast = Forecast;
|
| | | if(!forecast.GetPi())
|
| | | ReturnFalse;
|
| | | if(!CNeuronMSRes::calcInputGradients(cMHAOutput.AsObject()))
|
| | | ReturnFalse;
|
| | | if(!DeActivation(cOutputProjection.getOutput(), cOutputProjection.getGradient(), cMHAOutput.getGradient(),
|
| | | cOutputProjection.Activation()))
|
| | | ReturnFalse;
|
| | | if(!DeActivation(cQueryResidual.getOutput(), cQueryResidual.getGradient(), cMHAOutput.getGradient(),
|
| | | cQueryResidual.Activation()))
|
| | | ReturnFalse;
|
| | | if(!cHeadGateTranspose.CalcHiddenGradients(cOutputProjection.AsObject()))
|
| | | ReturnFalse;
|
| | | if(!cHeadGate.CalcHiddenGradients(cHeadGateTranspose.AsObject()))
|
| | | ReturnFalse;
|
| | | if(!bCritic)
|
| | | {
|
| | | if(!ScalarToVector(forecast.GetPi(), cHeadGate.getGradient(), cScenarioHistory.getGradient(),
|
| | | iQueries * iDimension))
|
| | | ReturnFalse;
|
| | | if(!cAttentionTranspose.CalcHiddenGradients(cScenarioHistory.AsObject(), cHistoryContext.getOutput(),
|
| | | cHistoryContext.getGradient(), None))
|
| | | ReturnFalse;
|
| | | if(!cHistoryTTM.CalcHiddenGradients(cHistoryContext.AsObject(), cHistoryMarket.getOutput(),
|
| | | cHistoryMarket.getGradient(), None))
|
| | | ReturnFalse;
|
| | | if(!cAttentionTranspose.CalcHiddenGradients(cHistoryTTM.AsObject(), cHistoryStack.getOutput(), NULL, None))
|
| | | ReturnFalse;
|
| | | if(!cHistoryStack.CalcHiddenGradients(cHistoryMarket.AsObject(), cHistoryTokenProjection.getOutput(),
|
| | | cHistoryTokenProjection.getGradient(), None))
|
| | | ReturnFalse;
|
| | | if(!cTokenPE.CalcHiddenGradients(cHistoryTokenProjection.AsObject()))
|
| | | ReturnFalse;
|
| | | }
|
| | | else
|
| | | if(!ScalarToVector(forecast.GetPi(), cHeadGate.getGradient(), cAttentionTranspose.getGradient(),
|
| | | iQueries * iDimension))
|
| | | ReturnFalse;
|
| | | if(!cAttention.CalcHiddenGradients(cAttentionTranspose.AsObject()))
|
| | | ReturnFalse;
|
| | | if(!cQueryGradient.CalcHiddenGradients(cQueryResidual.AsObject()))
|
| | | ReturnFalse;
|
| | | if(TaskSkillEnabled())
|
| | | {
|
2026-08-20 22:59:48 +03:00 | | | //--- Attention owns the two-input gradient dispatcher. Passing the Bank as
|
| | | //--- its query input writes dL/d(Bank output) to the Bank without weights.
|
2026-08-20 19:55:53 +03:00 | | | if(!m_task_bank.CalcHiddenGradients(cAttention.AsObject(), cKV.getOutput(),
|
| | | cKV.getGradient(), None))
|
| | | ReturnFalse;
|
2026-08-20 22:59:48 +03:00 | | | if((m_mode == D2_EVALUATE || m_mode == D2_ONLINE_CALIBRATION) &&
|
| | | !m_task_bank.AccumulateInfluenceFromGradient(m_task_bank.getGradient()))
|
| | | ReturnFalse;
|
2026-08-20 19:55:53 +03:00 | | | if(!cQueryProjection.CalcHiddenGradients(m_task_bank.AsObject()))
|
| | | ReturnFalse;
|
| | | }
|
| | | else
|
| | | if(!cQueryProjection.CalcHiddenGradients(cAttention.AsObject(), cKV.getOutput(),
|
| | | cKV.getGradient(), None))
|
| | | ReturnFalse;
|
| | | if(!SumAndNormalize(cQueryProjection.getGradient(), cQueryGradient.getGradient(), cQueryProjection.getGradient(),
|
| | | 1, false, 0, 0, 0, 1))
|
| | | ReturnFalse;
|
| | | if(!DeConcat(cKVGradK.getGradient(), cKVGradV.getGradient(), cKV.getGradient(),
|
| | | iScenarios * iDimension, iScenarios * iDimension, iVariables * iHorizon))
|
| | | ReturnFalse;
|
| | | if(!SumAndNormalize(cKVGradK.getGradient(), cKVGradV.getGradient(),
|
| | | cTokensTranspose.getGradient(), 1, false, 0, 0, 0, 1))
|
| | | ReturnFalse;
|
2026-08-20 22:59:48 +03:00 | | | if(!cTokenPE.CalcHiddenGradients(cTokensTranspose.AsObject()))
|
| | | ReturnFalse;
|
| | | if(!cTokenSum.CalcHiddenGradients(cTokenPE.AsObject()))
|
| | | ReturnFalse;
|
2026-08-20 19:55:53 +03:00 | | | if(StepSkillEnabled())
|
| | | {
|
2026-08-20 22:59:48 +03:00 | | | //--- As for Task, Step has no weights. Its output is the corrected cWz,
|
| | | //--- therefore the token-sum gradient is passed through unchanged to cWz.
|
| | | if(!CopyBufferRaw(cTokenSum.getGradient(), m_step_bank.getGradient(),
|
| | | m_step_bank.Neurons()) ||
|
| | | !m_step_bank.calcInputGradients(cWz.AsObject()))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-20 22:59:48 +03:00 | | | if((m_mode == D2_EVALUATE || m_mode == D2_ONLINE_CALIBRATION) &&
|
| | | !m_step_bank.AccumulateInfluenceFromGradient(m_step_bank.getGradient()))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
| | | }
|
| | | else
|
2026-08-20 22:59:48 +03:00 | | | if(!Concat(cTokenSum.getGradient(), cTokenSum.getGradient(), cWz.getGradient(),
|
| | | iScenarios * iVariables * iHorizon * iDimension, 0, 1))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
| | | if(!Concat(cTokenSum.getGradient(), cTokenSum.getGradient(), cWu.getGradient(),
|
2026-08-20 22:59:48 +03:00 | | | iScenarios * iVariables * iHorizon * iDimension, 0, 1))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
| | | if(!NeuronOCL.CalcHiddenGradients(cQueryProjection.AsObject()))
|
| | | ReturnFalse;
|
2026-08-20 22:59:48 +03:00 | | | if(SkillUpdatesEnabled() && m_task_bank.Enabled() &&
|
| | | !m_task_bank.UpdateFromGradient(cQueryProjection.getOutput(), cQueryProjection.getGradient()))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-20 22:59:48 +03:00 | | | if(SkillUpdatesEnabled() && m_step_bank.Enabled() &&
|
| | | !m_step_bank.UpdateFromGradient(cWz.getOutput(), cWz.getGradient()))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-21 08:18:10 +03:00 | | | if(!UpdateOnlineDirection(GetPointer(m_task_bank), m_task_bank.getGradient()) ||
|
| | | !UpdateOnlineDirection(GetPointer(m_step_bank), m_step_bank.getGradient()))
|
| | | ReturnFalse;
|
2026-08-20 19:55:53 +03:00 | | | if(NeuronOCL.Activation() != None)
|
| | | return(DeActivation(NeuronOCL.getOutput(), NeuronOCL.getGradient(), NeuronOCL.getGradient(),
|
| | | NeuronOCL.Activation()));
|
| | | return(true);
|
2026-08-18 19:58:41 +03:00 | | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Updates the second-pass attention weights; bank weights stay |
|
| | | //| untouched. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | bool CD2Skill::updateInputWeightsSecond(CNeuronBaseOCL *NeuronOCL,
|
| | | CNeuronBaseOCL *Forecast)
|
2026-08-18 19:58:41 +03:00 | | | {
|
2026-08-20 19:55:53 +03:00 | | | if(!NeuronOCL || !Forecast || Forecast.Type() != defNeuronScenarioForecast)
|
| | | ReturnFalse;
|
2026-08-20 22:59:48 +03:00 | | | //--- Collection records bank observations but freezes the Actor highway.
|
2026-08-27 11:39:46 +03:00 | | | //--- Evaluation, inference, and online calibration are read-only for Actor weights.
|
| | | if(m_mode == D2_COLLECT || m_mode == D2_EVALUATE || m_mode == D2_INFERENCE ||
|
| | | m_mode == D2_ONLINE_CALIBRATION)
|
2026-08-20 22:59:48 +03:00 | | | return(true);
|
2026-08-20 19:55:53 +03:00 | | | CNeuronScenarioForecast *forecast = Forecast;
|
| | | if(!forecast.GetLogU())
|
| | | ReturnFalse;
|
| | | if(!cQueryProjection.UpdateInputWeights(NeuronOCL))
|
| | | ReturnFalse;
|
| | | if(!cWz.UpdateInputWeights(Forecast))
|
| | | ReturnFalse;
|
| | | if(!cWu.UpdateInputWeightsBuffer(forecast.GetLogU()))
|
| | | ReturnFalse;
|
| | | if(!cTokenPE.UpdateInputWeights(cTokenSum.AsObject()))
|
| | | ReturnFalse;
|
| | | if(!cOutputProjection.UpdateInputWeights(cHeadGateTranspose.AsObject()))
|
| | | ReturnFalse;
|
| | | if(!cQueryResidual.UpdateInputWeights(cQueryProjection.AsObject()))
|
| | | ReturnFalse;
|
| | | if(!bCritic)
|
| | | {
|
| | | if(!cHistoryTokenProjection.UpdateInputWeights(cTokenPE.AsObject()))
|
| | | ReturnFalse;
|
| | | if(!cHistoryMarket.UpdateInputWeights(cHistoryStack.AsObject(), cHistoryTokenProjection.getOutput()))
|
| | | ReturnFalse;
|
| | | if(!cHistoryContext.UpdateInputWeights(cHistoryTTM.AsObject(), cHistoryMarket.getOutput()))
|
| | | ReturnFalse;
|
| | | if(!cScenarioHistory.UpdateInputWeights(cAttentionTranspose.AsObject(), cHistoryContext.getOutput()))
|
| | | ReturnFalse;
|
| | | }
|
| | | return(true);
|
2026-08-18 19:58:41 +03:00 | | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Saves the skill and both banks to the file handle. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-18 19:58:41 +03:00 | | | bool CD2Skill::Save(const int file_handle)
|
| | | {
|
| | | if(!m_ready || !CNeuronScenarioCrossAttention::Save(file_handle))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | dFileWriteUInt(file_handle, D2SKILL_LAYER_FORMAT);
|
| | | return(m_task_bank.Save(file_handle) && m_step_bank.Save(file_handle));
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Restores the skill and both banks, validating restored bank |
|
| | | //| shapes. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-18 19:58:41 +03:00 | | | bool CD2Skill::Load(const int file_handle)
|
| | | {
|
| | | if(file_handle == INVALID_HANDLE || !CNeuronScenarioCrossAttention::Load(file_handle))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | const uint format = (uint)FileReadInteger(file_handle);
|
| | | if(format != D2SKILL_LAYER_FORMAT || bCritic || !OpenCL)
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | m_ready = false;
|
2026-08-26 18:00:29 +03:00 | | | m_task_bank_materialized = false;
|
| | | m_step_bank_materialized = false;
|
| | | //--- Serialized bank shapes are restored by Load(). SetOpenCL() creates
|
| | | //--- scratch and is invalid before those dimensions exist.
|
| | | m_task_bank.AttachOpenCL(OpenCL);
|
| | | m_step_bank.AttachOpenCL(OpenCL);
|
2026-08-18 19:58:41 +03:00 | | | if(FileReadInteger(file_handle, INT_VALUE) != defNeuronD2SkillBank ||
|
| | | !m_task_bank.Load(file_handle) ||
|
| | | FileReadInteger(file_handle, INT_VALUE) != defNeuronD2SkillBank ||
|
| | | !m_step_bank.Load(file_handle))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | const uint task_dimension = iQueries * iScenarios * iDimension;
|
| | | const uint step_dimension = iScenarios * iVariables * iHorizon * iDimension;
|
| | | if(m_task_bank.Dimension() != task_dimension || m_task_bank.Slots() != iScenarios ||
|
| | | m_step_bank.Dimension() != step_dimension || m_step_bank.Slots() != iScenarios)
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | m_ready = true;
|
| | | return(true);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Restores the skill from file and attaches the given OpenCL |
|
| | | //| context. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-18 19:58:41 +03:00 | | | bool CD2Skill::Load(const int file_handle, COpenCLMy *opencl)
|
| | | {
|
| | | if(file_handle == INVALID_HANDLE || !opencl || FileReadInteger(file_handle) != Type())
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | OpenCL = opencl;
|
| | | return(Load(file_handle));
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Rebinds the skill GPU buffers to the given OpenCL context. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-18 19:58:41 +03:00 | | | void CD2Skill::SetOpenCL(COpenCLMy *opencl)
|
| | | {
|
| | | CNeuronScenarioCrossAttention::SetOpenCL(opencl);
|
2026-08-26 18:00:29 +03:00 | | | //--- Disabled checkpoint banks retain their host state but defer GPU scratch
|
| | | //--- until the runtime mode explicitly enables the respective branch. Do not
|
| | | //--- AttachOpenCL() here: it would replace only the bank pointer, causing the
|
| | | //--- later SetOpenCL() to skip the inherited Output/Gradient rebind.
|
| | | if(m_task_bank_materialized)
|
| | | m_task_bank.SetOpenCL(opencl);
|
| | | if(m_step_bank_materialized)
|
| | | m_step_bank.SetOpenCL(opencl);
|
2026-08-18 19:58:41 +03:00 | | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Propagates the training flag to the skill and both banks. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-18 19:58:41 +03:00 | | | void CD2Skill::TrainMode(bool flag)
|
| | | {
|
| | | CNeuronScenarioCrossAttention::TrainMode(flag);
|
| | | m_task_bank.TrainMode(flag);
|
| | | m_step_bank.TrainMode(flag);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Polyak-averages the base attention weights; bank parameters are |
|
| | | //| excluded. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-18 19:58:41 +03:00 | | | bool CD2Skill::WeightsUpdate(CNeuronBaseOCL *source, float tau)
|
| | | {
|
| | | if(!source || source.Type() != Type())
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
| | | //--- Skill banks are accumulated model parameters, not trainable copies of
|
| | | //--- the scenario-attention weights. Polyak update applies only to the base
|
| | | //--- attention highway.
|
| | | return(CNeuronScenarioCrossAttention::WeightsUpdate(source, tau));
|
2026-08-18 19:58:41 +03:00 | | | }
|
| | | //+------------------------------------------------------------------+
|
2026-08-21 08:18:10 +03:00 | | | //| Preserves COLLECT bank state while CNet weights are frozen. |
|
| | | //+------------------------------------------------------------------+
|
| | | bool CD2Skill::UpdateInputStateSecond(CObject *SourceObject,
|
| | | CNeuronBaseOCL *Forecast)
|
| | | {
|
| | | if(CheckPointer(SourceObject) == POINTER_INVALID || !Forecast || !m_ready)
|
| | | ReturnFalse;
|
| | | CNeuronBaseOCL *source = SourceObject;
|
| | | return(updateInputWeightsSecond(source, Forecast));
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Clears the recurrent execution state; banks survive as durable |
|
| | | //| model parameters. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-18 19:58:41 +03:00 | | | bool CD2Skill::Clear(void)
|
| | | {
|
2026-08-20 19:55:53 +03:00 | | | //--- Clear resets only the recurrent execution state inherited from the
|
| | | //--- attention layer. Banks are durable model parameters and survive it.
|
| | | const bool ready = m_ready;
|
| | | if(!CNeuronScenarioCrossAttention::Clear())
|
| | | ReturnFalse;
|
| | | m_ready = ready;
|
| | | return(true);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Sets the skill runtime mode. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | bool CD2Skill::SetMode(const ENUM_D2SKILL_MODE mode)
|
| | | {
|
| | | if(mode < D2_DISABLED || mode > D2_ONLINE_CALIBRATION)
|
| | | ReturnFalse;
|
| | | m_mode = mode;
|
| | | return(true);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Configures the optional online direction-only EMA. |
|
2026-08-21 08:18:10 +03:00 | | | //+------------------------------------------------------------------+
|
| | | bool CD2Skill::SetOnlineDirectionUpdate(const bool enabled)
|
| | | {
|
| | | m_online_direction_update = enabled;
|
| | | return(true);
|
| | | }
|
2026-09-04 17:39:51 +03:00 | | | //+------------------------------------------------------------------+
|
| | | //| Resets the episode influence counters of both banks. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | bool CD2Skill::ResetEpisodeInfluence(void)
|
| | | {
|
| | | if(!m_ready || !m_task_bank.ResetEpisodeInfluence() ||
|
| | | !m_step_bank.ResetEpisodeInfluence())
|
| | | ReturnFalse;
|
| | | return(true);
|
2026-08-18 19:58:41 +03:00 | | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Combines the source with the item correction (or the source |
|
| | | //| alone) into the output. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-18 19:58:41 +03:00 | | | bool CD2SkillItem::feedForward(CNeuronBaseOCL *NeuronOCL)
|
| | | {
|
| | | if(!OpenCL || CheckPointer(NeuronOCL) == POINTER_INVALID ||
|
| | | CheckPointer(Output) == POINTER_INVALID)
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | CBufferFloat *source = NeuronOCL.getOutput();
|
| | | if(!source || source.Total() != Output.Total() || source.GetOpenCL() != OpenCL)
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | if(CheckPointer(m_correction) == POINTER_INVALID)
|
| | | return(SumAndNormalize(source, source, Output, source.Total(), false,
|
| | | 0, 0, 0, 0.5f));
|
| | | return(SumAndNormalize(source, m_correction, Output, source.Total(), false,
|
| | | 0, 0, 0, 1.0f));
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Passes the incoming gradient through, preserving gradients |
|
| | | //| accumulated by other branches. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-18 19:58:41 +03:00 | | | bool CD2SkillItem::calcInputGradients(CNeuronBaseOCL *NeuronOCL)
|
| | | {
|
| | | if(!OpenCL || CheckPointer(NeuronOCL) == POINTER_INVALID ||
|
| | | CheckPointer(Gradient) == POINTER_INVALID)
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | CBufferFloat *source_gradient = NeuronOCL.getGradient();
|
| | | if(!source_gradient || source_gradient.Total() != Gradient.Total() ||
|
| | | source_gradient.GetOpenCL() != OpenCL)
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | //--- A skill item has no weights: dL/dx receives dL/dy. Preserve any
|
| | | //--- gradient already accumulated by another branch (for example the
|
| | | //--- Actor history path) and add the bank output gradient on the device.
|
| | | return(SumAndNormalize(source_gradient, Gradient, source_gradient,
|
| | | Gradient.Total(), false, 0, 0, 0, 1.0f));
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Allocates and binds all item GPU buffers. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-18 19:58:41 +03:00 | | | bool CD2SkillItem::EnsureItemState(void)
|
| | | {
|
| | | if(!OpenCL || m_item_dimension == 0)
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | if(m_item_correction.Total() != (int)m_item_dimension &&
|
| | | !m_item_correction.BufferInit((int)m_item_dimension, 0.0f))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | if((m_item_correction.GetOpenCL() != OpenCL || m_item_correction.GetIndex() < 0) &&
|
| | | !m_item_correction.BufferCreate(OpenCL))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | if(m_correction == NULL)
|
| | | {
|
| | | m_correction = GetPointer(m_item_correction);
|
| | | }
|
| | | if(m_item_direction.Total() != (int)m_item_dimension &&
|
| | | !m_item_direction.BufferInit((int)m_item_dimension, 0.0f))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | if((m_item_direction.GetOpenCL() != OpenCL || m_item_direction.GetIndex() < 0) &&
|
| | | !m_item_direction.BufferCreate(OpenCL))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | if(m_item_scale.Total() != 1 && !m_item_scale.BufferInit(1, 0.0f))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | if((m_item_scale.GetOpenCL() != OpenCL || m_item_scale.GetIndex() < 0) &&
|
| | | !m_item_scale.BufferCreate(OpenCL))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | if(m_item_observations.Total() != 1 && !m_item_observations.BufferInit(1, 0.0f))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | if((m_item_observations.GetOpenCL() != OpenCL || m_item_observations.GetIndex() < 0) &&
|
| | | !m_item_observations.BufferCreate(OpenCL))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | if(m_item_mass.Total() != 1 && !m_item_mass.BufferInit(1, 0.0f))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | if((m_item_mass.GetOpenCL() != OpenCL || m_item_mass.GetIndex() < 0) &&
|
| | | !m_item_mass.BufferCreate(OpenCL))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | return(m_correction && m_correction.GetOpenCL() == OpenCL &&
|
2026-08-20 19:55:53 +03:00 | | | m_correction.Total() == (int)m_item_dimension &&
|
| | | m_correction.GetIndex() >= 0 && m_item_direction.GetIndex() >= 0 &&
|
| | | m_item_scale.GetIndex() >= 0 && m_item_observations.GetIndex() >= 0 &&
|
| | | m_item_mass.GetIndex() >= 0 && EnsureItemScratch());
|
2026-08-18 19:58:41 +03:00 | | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-14 09:56:18 +03:00 | | | //| Prepares legitimately absent Item-owned host buffers only. |
|
| | | //+------------------------------------------------------------------+
|
| | | bool CD2SkillItem::PrepareItemOwnedCheckedState(void)
|
| | | {
|
| | | if(CheckPointer(OpenCL) == POINTER_INVALID || m_item_dimension == 0 ||
|
| | | CheckPointer(Output) == POINTER_INVALID || CheckPointer(Gradient) == POINTER_INVALID ||
|
| | | Output.Total() != (int)m_item_dimension || Gradient.Total() != (int)m_item_dimension ||
|
| | | (Output.GetIndex() >= 0 && CheckPointer(Output.GetOpenCL()) == POINTER_INVALID) ||
|
| | | (Gradient.GetIndex() >= 0 && CheckPointer(Gradient.GetOpenCL()) == POINTER_INVALID))
|
| | | return(false);
|
| | |
|
| | | uint local_size = 0;
|
| | | uint groups = 0;
|
| | | uint partial_count = 0;
|
| | | if(!ItemLaunchLayout(local_size, groups, partial_count))
|
| | | return(false);
|
| | |
|
| | | CBufferFloat *buffers[7];
|
| | | int totals[7];
|
| | | string slots[7] = {"correction", "direction", "scale", "observations",
|
| | | "mass", "norm partials", "reduced norm"};
|
| | | buffers[0] = GetPointer(m_item_correction);
|
| | | totals[0] = (int)m_item_dimension;
|
| | | buffers[1] = GetPointer(m_item_direction);
|
| | | totals[1] = (int)m_item_dimension;
|
| | | buffers[2] = GetPointer(m_item_scale);
|
| | | totals[2] = 1;
|
| | | buffers[3] = GetPointer(m_item_observations);
|
| | | totals[3] = 1;
|
| | | buffers[4] = GetPointer(m_item_mass);
|
| | | totals[4] = 1;
|
| | | buffers[5] = GetPointer(m_item_partials);
|
| | | totals[5] = (int)partial_count;
|
| | | buffers[6] = GetPointer(m_item_reduced_norm);
|
| | | totals[6] = 2;
|
| | |
|
| | | for(int i = 0; i < 7; i++)
|
| | | {
|
| | | if(CheckPointer(buffers[i]) == POINTER_INVALID ||
|
| | | (buffers[i].Total() != totals[i] &&
|
| | | (buffers[i].Total() != 0 || buffers[i].GetIndex() >= 0)) ||
|
| | | (buffers[i].GetIndex() >= 0 &&
|
| | | CheckPointer(buffers[i].GetOpenCL()) == POINTER_INVALID))
|
| | | ReturnFalseEx("item " + slots[i] + " checked state");
|
| | | }
|
| | |
|
| | | for(int i = 0; i < 7; i++)
|
| | | if(buffers[i].Total() == 0 && !buffers[i].BufferInit(totals[i], 0.0f))
|
| | | ReturnFalseEx("item " + slots[i] + " host init");
|
| | |
|
| | | return(true);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Computes the GPU launch layout and norm-reduction scratch size |
|
| | | //| for the item. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-18 19:58:41 +03:00 | | | bool CD2SkillItem::ItemLaunchLayout(uint &local_size, uint &groups,
|
| | | uint &partial_count) const
|
| | | {
|
| | | if(!OpenCL || m_item_dimension == 0)
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
| | | long limit = OpenCL.GetMaxWorkGroupSize();
|
2026-08-18 19:58:41 +03:00 | | | limit = MathMin(limit, OpenCL.GetMaxLocalSize(0));
|
| | | if(limit <= 0)
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | local_size = 1;
|
| | | while(local_size <= (uint)limit / 2)
|
| | | local_size *= 2;
|
2026-08-20 19:55:53 +03:00 | | | groups = (m_item_dimension + local_size - 1) / local_size;
|
| | | ulong count = m_item_dimension;
|
2026-08-18 19:58:41 +03:00 | | | ulong total = count;
|
| | | while(count > 1)
|
| | | {
|
2026-08-20 19:55:53 +03:00 | | | count = (count + 1) / 2;
|
2026-08-18 19:58:41 +03:00 | | | if(count > 1)
|
| | | total += count;
|
| | | }
|
| | | if(total == 0 || total > 2147483647)
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | partial_count = (uint)total;
|
| | | return(true);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Allocates the item norm-reduction scratch buffers. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-18 19:58:41 +03:00 | | | bool CD2SkillItem::EnsureItemScratch(void)
|
| | | {
|
| | | uint local_size = 0;
|
| | | uint groups = 0;
|
| | | uint partial_count = 0;
|
| | | if(!ItemLaunchLayout(local_size, groups, partial_count))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | if(m_item_partials.Total() != (int)partial_count &&
|
| | | !m_item_partials.BufferInit(partial_count, 0.0f))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | if((m_item_partials.GetOpenCL() != OpenCL || m_item_partials.GetIndex() < 0) &&
|
| | | !m_item_partials.BufferCreate(OpenCL))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-22 20:08:02 +03:00 | | | if(m_item_reduced_norm.Total() != 2 && !m_item_reduced_norm.BufferInit(2, 0.0f))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | if((m_item_reduced_norm.GetOpenCL() != OpenCL || m_item_reduced_norm.GetIndex() < 0) &&
|
| | | !m_item_reduced_norm.BufferCreate(OpenCL))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | return(true);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Runs the staged GPU reduction that computes the item vector norm.|
|
| | | //+------------------------------------------------------------------+
|
2026-08-18 19:58:41 +03:00 | | | bool CD2SkillItem::CalculateItemNorm(CBufferFloat *source, const uint local_size,
|
| | | const uint groups)
|
| | | {
|
| | | if(!source || source.GetOpenCL() != OpenCL || source.GetIndex() < 0 ||
|
| | | local_size == 0 || groups == 0)
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | const int partial_kernel = def_k_D2SkillItemPartial;
|
| | | setBuffer(partial_kernel, def_k_d2ip_source, source.GetIndex())
|
| | | setBuffer(partial_kernel, def_k_d2ip_partials, m_item_partials.GetIndex())
|
| | | setArgument(partial_kernel, def_k_d2ip_dimension, (int)m_item_dimension)
|
| | | setArgument(partial_kernel, def_k_d2ip_output_offset, 0)
|
| | | uint offset[] = {0};
|
| | | uint global[] = {groups * local_size};
|
| | | uint local[] = {local_size};
|
| | | kernelExecuteLoc(partial_kernel, offset, global, local)
|
| | | //--- Recursively reduce into disjoint regions of the scratch buffer. The
|
| | | //--- final scalar is written to its dedicated non-persistent buffer.
|
2026-08-20 19:55:53 +03:00 | | | uint input_count = m_item_dimension;
|
2026-08-18 19:58:41 +03:00 | | | uint input_offset = 0;
|
2026-08-20 19:55:53 +03:00 | | | uint output_offset = m_item_dimension;
|
2026-08-18 19:58:41 +03:00 | | | const int reduce_kernel = def_k_D2SkillItemReduce;
|
| | | while(input_count > 0)
|
| | | {
|
2026-08-20 19:55:53 +03:00 | | | const uint reduce_groups = (input_count + 1) / 2;
|
2026-08-18 19:58:41 +03:00 | | | const int final_output = (reduce_groups == 1 ? 1 : 0);
|
| | | setBuffer(reduce_kernel, def_k_d2ir_partials, m_item_partials.GetIndex())
|
| | | setBuffer(reduce_kernel, def_k_d2ir_reduced, m_item_reduced_norm.GetIndex())
|
| | | setArgument(reduce_kernel, def_k_d2ir_input_count, (int)input_count)
|
| | | setArgument(reduce_kernel, def_k_d2ir_input_offset, (int)input_offset)
|
| | | setArgument(reduce_kernel, def_k_d2ir_output_offset, (int)output_offset)
|
| | | setArgument(reduce_kernel, def_k_d2ir_final_output, final_output)
|
2026-08-20 19:55:53 +03:00 | | | const uint padded = ((reduce_groups + local_size - 1) / local_size) * local_size;
|
| | | uint reduce_global[] = {padded};
|
2026-08-18 19:58:41 +03:00 | | | uint reduce_local[] = {local_size};
|
| | | kernelExecuteLoc(reduce_kernel, offset, reduce_global, reduce_local)
|
| | | if(final_output != 0)
|
| | | break;
|
| | | input_count = reduce_groups;
|
| | | input_offset = output_offset;
|
| | | output_offset += reduce_groups;
|
| | | }
|
| | | return(true);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Applies the EMA update of correction, direction and magnitude |
|
| | | //| from the gradient. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-18 19:58:41 +03:00 | | | bool CD2SkillItem::UpdateFromGradient(CBufferFloat *gradient)
|
| | | {
|
| | | if(!gradient || !OpenCL || gradient.GetOpenCL() != OpenCL ||
|
| | | gradient.Total() != (int)m_item_dimension || gradient.GetIndex() < 0 ||
|
| | | !EnsureItemState())
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | uint local_size = 0;
|
| | | uint groups = 0;
|
| | | uint partial_count = 0;
|
| | | if(!ItemLaunchLayout(local_size, groups, partial_count) ||
|
| | | !CalculateItemNorm(gradient, local_size, groups))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | const int kernel = def_k_D2SkillItemApply;
|
| | | setBuffer(kernel, def_k_d2ia_gradient, gradient.GetIndex())
|
| | | setBuffer(kernel, def_k_d2ia_correction, m_correction.GetIndex())
|
| | | setBuffer(kernel, def_k_d2ia_direction, m_item_direction.GetIndex())
|
| | | setBuffer(kernel, def_k_d2ia_scale, m_item_scale.GetIndex())
|
| | | setBuffer(kernel, def_k_d2ia_observations, m_item_observations.GetIndex())
|
| | | setBuffer(kernel, def_k_d2ia_mass, m_item_mass.GetIndex())
|
| | | setBuffer(kernel, def_k_d2ia_reduced_norm, m_item_reduced_norm.GetIndex())
|
| | | setArgument(kernel, def_k_d2ia_dimension, (int)m_item_dimension)
|
| | | setArgument(kernel, def_k_d2ia_representation, (int)m_representation)
|
| | | setArgument(kernel, def_k_d2ia_beta_correction, m_beta_correction)
|
| | | setArgument(kernel, def_k_d2ia_beta_direction, m_beta_direction)
|
| | | setArgument(kernel, def_k_d2ia_beta_magnitude, m_beta_magnitude)
|
| | | setArgument(kernel, def_k_d2ia_phase, 0)
|
| | | uint offset[] = {0};
|
| | | uint global[] = {groups * local_size};
|
| | | uint local[] = {local_size};
|
| | | kernelExecuteLoc(kernel, offset, global, local)
|
| | | if(m_representation == D2SkillDirectionMagnitude)
|
| | | {
|
| | | if(!CalculateItemNorm(GetPointer(m_item_direction), local_size, groups))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | setArgument(kernel, def_k_d2ia_phase, 1)
|
| | | kernelExecuteLoc(kernel, offset, global, local)
|
| | | }
|
| | | //---
|
| | | return(true);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Saves the item state to the file handle. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-18 19:58:41 +03:00 | | | bool CD2SkillItem::Save(const int file_handle)
|
| | | {
|
| | | if(file_handle == INVALID_HANDLE || !CNeuronBaseOCL::Save(file_handle) ||
|
| | | m_item_dimension == 0 || !EnsureItemState())
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | dFileWriteUInt(file_handle, D2SKILL_ITEM_FORMAT);
|
| | | dFileWriteUInt(file_handle, m_item_dimension);
|
| | | dFileWriteUInt(file_handle, (uint)m_representation);
|
| | | dFileWriteFloat(file_handle, m_beta_correction);
|
| | | dFileWriteFloat(file_handle, m_beta_direction);
|
| | | dFileWriteFloat(file_handle, m_beta_magnitude);
|
| | | return(m_item_correction.Save(file_handle) && m_item_direction.Save(file_handle) &&
|
| | | m_item_scale.Save(file_handle) && m_item_observations.Save(file_handle) &&
|
| | | m_item_mass.Save(file_handle));
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Restores the item state from the file handle. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-18 19:58:41 +03:00 | | | bool CD2SkillItem::Load(const int file_handle)
|
| | | {
|
| | | if(file_handle == INVALID_HANDLE || !CNeuronBaseOCL::Load(file_handle))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | const uint format = (uint)FileReadInteger(file_handle);
|
| | | if(format != D2SKILL_ITEM_FORMAT)
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | m_item_dimension = (uint)FileReadInteger(file_handle);
|
| | | m_representation = (ED2SkillRepresentation)FileReadInteger(file_handle);
|
| | | dFileReadUFloat(file_handle, m_beta_correction);
|
| | | dFileReadUFloat(file_handle, m_beta_direction);
|
| | | dFileReadUFloat(file_handle, m_beta_magnitude);
|
| | | if(m_item_dimension == 0 || m_representation < D2SkillFullResidual ||
|
| | | m_representation > D2SkillDirectionMagnitude)
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | if(!m_item_correction.Load(file_handle) || !m_item_direction.Load(file_handle) ||
|
| | | !m_item_scale.Load(file_handle) || !m_item_observations.Load(file_handle) ||
|
| | | !m_item_mass.Load(file_handle))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | if(m_item_correction.Total() != (int)m_item_dimension ||
|
| | | m_item_direction.Total() != (int)m_item_dimension || m_item_scale.Total() != 1 ||
|
| | | m_item_observations.Total() != 1 || m_item_mass.Total() != 1)
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | SetOpenCL(OpenCL);
|
| | | m_correction = GetPointer(m_item_correction);
|
| | | return(m_correction.GetOpenCL() == OpenCL && m_correction.GetIndex() >= 0);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Restores the item state and attaches the given OpenCL context. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-18 19:58:41 +03:00 | | | bool CD2SkillItem::Load(const int file_handle, COpenCLMy *opencl)
|
| | | {
|
| | | if(file_handle == INVALID_HANDLE || !opencl ||
|
| | | FileReadInteger(file_handle, INT_VALUE) != Type())
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | AttachOpenCL(opencl);
|
| | | return(Load(file_handle));
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Rebinds all item GPU buffers to the given OpenCL context. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-18 19:58:41 +03:00 | | | void CD2SkillItem::SetOpenCL(COpenCLMy *obj)
|
| | | {
|
| | | if(!obj)
|
| | | return;
|
| | | CNeuronBaseOCL::SetOpenCL(obj);
|
| | | RebindItemBuffer(m_item_correction, obj);
|
| | | RebindItemBuffer(m_item_direction, obj);
|
| | | RebindItemBuffer(m_item_scale, obj);
|
| | | RebindItemBuffer(m_item_observations, obj);
|
| | | RebindItemBuffer(m_item_mass, obj);
|
| | | RebindItemBuffer(m_item_partials, obj);
|
| | | RebindItemBuffer(m_item_reduced_norm, obj);
|
| | | EnsureItemScratch();
|
| | | if(m_item_correction.Total() > 0 && m_item_correction.GetIndex() >= 0)
|
| | | m_correction = GetPointer(m_item_correction);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-14 09:56:18 +03:00 | | | //| Validates Item-owned checked state without alias policy. |
|
| | | //+------------------------------------------------------------------+
|
| | | bool CD2SkillItem::ValidateItemOwnedCheckedState(const bool allow_missing) const
|
| | | {
|
| | | //--- Validate the fixed item geometry and the inherited live owners.
|
| | | if(CheckPointer(OpenCL) == POINTER_INVALID ||
|
| | | m_item_dimension == 0 || m_item_dimension > (uint)INT_MAX ||
|
| | | CheckPointer(Output) == POINTER_INVALID || CheckPointer(Gradient) == POINTER_INVALID ||
|
| | | Output.Total() != (int)m_item_dimension || Gradient.Total() != (int)m_item_dimension ||
|
| | | (Output.GetIndex() >= 0 && CheckPointer(Output.GetOpenCL()) == POINTER_INVALID) ||
|
| | | (Gradient.GetIndex() >= 0 && CheckPointer(Gradient.GetOpenCL()) == POINTER_INVALID))
|
| | | return(false);
|
| | |
|
| | | //--- Obtain the existing reduction layout without allocating or rebinding scratch.
|
| | | uint local_size = 0;
|
| | | uint groups = 0;
|
| | | uint partial_count = 0;
|
| | | if(!ItemLaunchLayout(local_size, groups, partial_count))
|
| | | return(false);
|
| | |
|
| | | //--- Permit only wholly absent deferred Item slots; allocated slots retain live owners.
|
| | | const CBufferFloat *buffers[7];
|
| | | int totals[7];
|
| | | buffers[0] = GetPointer(m_item_correction);
|
| | | totals[0] = (int)m_item_dimension;
|
| | | buffers[1] = GetPointer(m_item_direction);
|
| | | totals[1] = (int)m_item_dimension;
|
| | | buffers[2] = GetPointer(m_item_scale);
|
| | | totals[2] = 1;
|
| | | buffers[3] = GetPointer(m_item_observations);
|
| | | totals[3] = 1;
|
| | | buffers[4] = GetPointer(m_item_mass);
|
| | | totals[4] = 1;
|
| | | buffers[5] = GetPointer(m_item_partials);
|
| | | totals[5] = (int)partial_count;
|
| | | buffers[6] = GetPointer(m_item_reduced_norm);
|
| | | totals[6] = 2;
|
| | | for(int i = 0; i < 7; i++)
|
| | | {
|
| | | if(CheckPointer(buffers[i]) == POINTER_INVALID ||
|
| | | (buffers[i].Total() != totals[i] &&
|
| | | (!allow_missing || buffers[i].Total() != 0 || buffers[i].GetIndex() >= 0)) ||
|
| | | (buffers[i].GetIndex() >= 0 &&
|
| | | CheckPointer(buffers[i].GetOpenCL()) == POINTER_INVALID))
|
| | | return(false);
|
| | | }
|
| | |
|
| | | //--- Finalize the Item-owned state validation without an alias policy.
|
| | | return(true);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
| | | //| Reports checked transfer support for an exact D2 skill item. |
|
| | | //+------------------------------------------------------------------+
|
| | | bool CD2SkillItem::SupportsOpenCLChecked(void) const
|
| | | {
|
| | | //--- Retain the exact Item type gate and the current correction-alias policy.
|
| | | if(Type() != defNeuronD2SkillItem || !ValidateItemOwnedCheckedState())
|
| | | return(false);
|
| | |
|
| | | //--- Validate the optional correction alias without constraining borrowed owners to the outer target.
|
| | | if(m_correction != NULL)
|
| | | {
|
| | | if(CheckPointer(m_correction) == POINTER_INVALID ||
|
| | | m_correction.Total() != (int)m_item_dimension)
|
| | | return(false);
|
| | |
|
| | | if(m_correction != GetPointer(m_item_correction) &&
|
| | | (CheckPointer(m_correction.GetOpenCL()) == POINTER_INVALID ||
|
| | | m_correction.GetIndex() < 0))
|
| | | return(false);
|
| | | }
|
| | |
|
| | | //--- Finalize without constraining an external correction alias to the outer owner.
|
| | | return(true);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
| | | //| Transfers owned item buffers before inherited context publication.|
|
| | | //+------------------------------------------------------------------+
|
| | | bool CD2SkillItem::SetOpenCLChecked(COpenCLMy *obj)
|
| | | {
|
| | | //--- Reject an invalid target, incomplete item or foreign borrowed correction before mutation.
|
| | | if(CheckPointer(obj) == POINTER_INVALID || !SupportsOpenCLChecked())
|
| | | ReturnFalseEx("checked item target or capability");
|
| | | if(m_correction != NULL && m_correction != GetPointer(m_item_correction) &&
|
| | | (CheckPointer(m_correction) == POINTER_INVALID ||
|
| | | m_correction.GetOpenCL() != obj ||
|
| | | m_correction.Total() != (int)m_item_dimension || m_correction.GetIndex() < 0))
|
| | | ReturnFalseEx("borrowed item correction target");
|
| | |
|
| | | //--- Read every allocated foreign direct buffer before any item buffer is recreated.
|
| | | if(m_item_correction.GetIndex() >= 0 &&
|
| | | CheckPointer(m_item_correction.GetOpenCL()) == POINTER_INVALID)
|
| | | ReturnFalseEx("item correction owner");
|
| | | if(m_item_correction.GetIndex() >= 0 && m_item_correction.GetOpenCL() != obj &&
|
| | | !m_item_correction.BufferRead())
|
| | | ReturnFalseEx("item correction read");
|
| | | if(m_item_direction.GetIndex() >= 0 &&
|
| | | CheckPointer(m_item_direction.GetOpenCL()) == POINTER_INVALID)
|
| | | ReturnFalseEx("item direction owner");
|
| | | if(m_item_direction.GetIndex() >= 0 && m_item_direction.GetOpenCL() != obj &&
|
| | | !m_item_direction.BufferRead())
|
| | | ReturnFalseEx("item direction read");
|
| | | if(m_item_scale.GetIndex() >= 0 &&
|
| | | CheckPointer(m_item_scale.GetOpenCL()) == POINTER_INVALID)
|
| | | ReturnFalseEx("item scale owner");
|
| | | if(m_item_scale.GetIndex() >= 0 && m_item_scale.GetOpenCL() != obj &&
|
| | | !m_item_scale.BufferRead())
|
| | | ReturnFalseEx("item scale read");
|
| | | if(m_item_observations.GetIndex() >= 0 &&
|
| | | CheckPointer(m_item_observations.GetOpenCL()) == POINTER_INVALID)
|
| | | ReturnFalseEx("item observations owner");
|
| | | if(m_item_observations.GetIndex() >= 0 && m_item_observations.GetOpenCL() != obj &&
|
| | | !m_item_observations.BufferRead())
|
| | | ReturnFalseEx("item observations read");
|
| | | if(m_item_mass.GetIndex() >= 0 &&
|
| | | CheckPointer(m_item_mass.GetOpenCL()) == POINTER_INVALID)
|
| | | ReturnFalseEx("item mass owner");
|
| | | if(m_item_mass.GetIndex() >= 0 && m_item_mass.GetOpenCL() != obj &&
|
| | | !m_item_mass.BufferRead())
|
| | | ReturnFalseEx("item mass read");
|
| | | if(m_item_partials.GetIndex() >= 0 &&
|
| | | CheckPointer(m_item_partials.GetOpenCL()) == POINTER_INVALID)
|
| | | ReturnFalseEx("item partials owner");
|
| | | if(m_item_partials.GetIndex() >= 0 && m_item_partials.GetOpenCL() != obj &&
|
| | | !m_item_partials.BufferRead())
|
| | | ReturnFalseEx("item partials read");
|
| | | if(m_item_reduced_norm.GetIndex() >= 0 &&
|
| | | CheckPointer(m_item_reduced_norm.GetOpenCL()) == POINTER_INVALID)
|
| | | ReturnFalseEx("item reduced norm owner");
|
| | | if(m_item_reduced_norm.GetIndex() >= 0 && m_item_reduced_norm.GetOpenCL() != obj &&
|
| | | !m_item_reduced_norm.BufferRead())
|
| | | ReturnFalseEx("item reduced norm read");
|
| | |
|
| | | //--- Recreate only direct item buffers that are foreign to the target or host-only.
|
| | | if(m_item_correction.GetOpenCL() != obj || m_item_correction.GetIndex() < 0)
|
| | | if(!m_item_correction.BufferCreate(obj))
|
| | | ReturnFalseEx("item correction create");
|
| | | if(m_item_direction.GetOpenCL() != obj || m_item_direction.GetIndex() < 0)
|
| | | if(!m_item_direction.BufferCreate(obj))
|
| | | ReturnFalseEx("item direction create");
|
| | | if(m_item_scale.GetOpenCL() != obj || m_item_scale.GetIndex() < 0)
|
| | | if(!m_item_scale.BufferCreate(obj))
|
| | | ReturnFalseEx("item scale create");
|
| | | if(m_item_observations.GetOpenCL() != obj || m_item_observations.GetIndex() < 0)
|
| | | if(!m_item_observations.BufferCreate(obj))
|
| | | ReturnFalseEx("item observations create");
|
| | | if(m_item_mass.GetOpenCL() != obj || m_item_mass.GetIndex() < 0)
|
| | | if(!m_item_mass.BufferCreate(obj))
|
| | | ReturnFalseEx("item mass create");
|
| | | if(m_item_partials.GetOpenCL() != obj || m_item_partials.GetIndex() < 0)
|
| | | if(!m_item_partials.BufferCreate(obj))
|
| | | ReturnFalseEx("item partials create");
|
| | | if(m_item_reduced_norm.GetOpenCL() != obj || m_item_reduced_norm.GetIndex() < 0)
|
| | | if(!m_item_reduced_norm.BufferCreate(obj))
|
| | | ReturnFalseEx("item reduced norm create");
|
| | |
|
| | | //--- Publish inherited owners only after every owned item buffer reached the target.
|
| | | if(!CNeuronBaseOCL::SetOpenCLChecked(obj))
|
| | | ReturnFalseEx("inherited item base context");
|
| | |
|
| | | //--- Finalize the checked item transfer without replacing the correction alias.
|
| | | return(true);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Clears all item buffers and drops the external correction |
|
| | | //| reference. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-18 19:58:41 +03:00 | | | bool CD2SkillItem::Clear(void)
|
| | | {
|
| | | m_correction = NULL;
|
| | | if(!CNeuronBaseOCL::Clear())
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | return((m_item_correction.Total() == 0 || m_item_correction.Fill(0)) &&
|
| | | (m_item_direction.Total() == 0 || m_item_direction.Fill(0)) &&
|
2026-08-20 19:55:53 +03:00 | | | (m_item_scale.Total() == 0 || m_item_scale.Fill(0)) &&
|
| | | (m_item_observations.Total() == 0 || m_item_observations.Fill(0)) &&
|
| | | (m_item_mass.Total() == 0 || m_item_mass.Fill(0)) &&
|
| | | (m_item_partials.Total() == 0 || m_item_partials.Fill(0)) &&
|
| | | (m_item_reduced_norm.Total() == 0 || m_item_reduced_norm.Fill(0)));
|
2026-08-18 19:58:41 +03:00 | | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Choose a D2 local size without changing the generic RAG width. |
|
2026-08-22 20:08:02 +03:00 | | | //+------------------------------------------------------------------+
|
| | | uint CD2SkillBank::D2LaunchLocalSize(const uint work_items) const
|
| | | {
|
| | | if(!OpenCL || work_items == 0)
|
| | | ReturnFalse;
|
| | | const long device_limit = MathMin(OpenCL.GetMaxWorkGroupSize(),
|
| | | OpenCL.GetMaxLocalSize(0));
|
| | | if(device_limit <= 0)
|
| | | ReturnFalse;
|
| | | const ulong capped_items = MathMin((ulong)device_limit,
|
| | | (ulong)MathMax(work_items, (uint)32));
|
| | | if(capped_items == 0)
|
| | | ReturnFalse;
|
| | | uint local_size = 1;
|
| | | while(local_size <= (uint)capped_items / 2)
|
| | | local_size *= 2;
|
| | | return(local_size);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Computes the GPU launch layout for the retrieval and Top-1 stage.|
|
| | | //+------------------------------------------------------------------+
|
2026-08-18 19:58:41 +03:00 | | | bool CD2SkillBank::RetrievalLaunchLayout(uint &local_size, uint &partial_count) const
|
| | | {
|
| | | if(!OpenCL || m_slots == 0 || m_dimension == 0 || m_slots > RAG_FLOAT_INDEX_LIMIT ||
|
| | | OpenCL.GetMaxWorkGroupSize() < RAG_TOPK_LOCAL_WIDTH ||
|
| | | OpenCL.GetMaxLocalSize(0) < RAG_TOPK_LOCAL_WIDTH)
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-22 20:08:02 +03:00 | | | const ulong score_items = (ulong)m_slots * m_dimension;
|
| | | if(score_items == 0 || score_items > UINT_MAX)
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-22 20:08:02 +03:00 | | | local_size = D2LaunchLocalSize((uint)score_items);
|
2026-08-18 19:58:41 +03:00 | | | partial_count = (m_slots + RAG_TOPK_LOCAL_WIDTH - 1) / RAG_TOPK_LOCAL_WIDTH;
|
| | | return(local_size > 0 && partial_count > 0);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Ensures a GPU buffer of the given size exists on the bank |
|
| | | //| context. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-18 19:58:41 +03:00 | | | bool CD2SkillBank::EnsureRetrievalBuffer(CBufferFloat &buffer, const int total)
|
| | | {
|
| | | if(!OpenCL || total <= 0)
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | if(buffer.Total() != total && !buffer.BufferInit(total, 0.0f))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | if(buffer.GetOpenCL() == OpenCL && buffer.GetIndex() >= 0)
|
| | | return(true);
|
| | | if(buffer.GetOpenCL() != NULL && buffer.GetIndex() >= 0)
|
| | | buffer.BufferFree();
|
| | | return(buffer.BufferCreate(OpenCL));
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Computes the staged radix-8 reduction scratch size. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | bool CD2SkillBank::ReductionScratchCount(const uint items, const uint batches,
|
| | | const uint fields, uint &total) const
|
| | | {
|
| | | const uint reduction_radix = 8;
|
| | | if(items == 0 || batches == 0 || fields == 0)
|
| | | ReturnFalse;
|
| | | ulong stage = items;
|
| | | ulong count = (ulong)batches * fields * stage;
|
| | | ulong required = count;
|
| | | while(stage > 1)
|
| | | {
|
| | | stage = (stage + reduction_radix - 1) / reduction_radix;
|
| | | if(stage > 1)
|
| | | {
|
| | | count = (ulong)batches * fields * stage;
|
| | | if(required > 2147483647 - count)
|
| | | ReturnFalse;
|
| | | required += count;
|
| | | }
|
| | | }
|
| | | if(required == 0 || required > 2147483647)
|
| | | ReturnFalse;
|
| | | total = (uint)required;
|
| | | return(true);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Runs the staged radix-8 GPU reduction from partials into reduced |
|
| | | //| metrics. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | bool CD2SkillBank::RunStagedReduction(CBufferFloat &partials, CBufferFloat &reduced,
|
| | | const uint items, const uint batches, const uint fields,
|
| | | const uint local_size, const int max_field_a,
|
| | | const int max_field_b)
|
| | | {
|
| | | const uint reduction_radix = 8;
|
| | | uint required = 0;
|
| | | const ulong reduced_total = (ulong)batches * fields;
|
| | | if(!OpenCL || local_size == 0 || !ReductionScratchCount(items, batches, fields, required) ||
|
| | | partials.GetOpenCL() != OpenCL || partials.GetIndex() < 0 ||
|
| | | partials.Total() < (int)required || reduced_total > 2147483647 ||
|
| | | reduced.GetOpenCL() != OpenCL || reduced.GetIndex() < 0 ||
|
| | | reduced.Total() < (int)reduced_total)
|
| | | ReturnFalse;
|
| | | uint input_count = items;
|
| | | uint input_offset = 0;
|
| | | uint output_offset = batches * items * fields;
|
| | | uint offset[1] = {0};
|
| | | const int kernel = def_k_D2SkillMetricReduce;
|
| | | while(input_count > 0)
|
| | | {
|
| | | const uint output_count = (input_count + reduction_radix - 1) / reduction_radix;
|
| | | const int final_output = (output_count == 1 ? 1 : 0);
|
| | | setBuffer(kernel, def_k_d2mr_partials, partials.GetIndex())
|
| | | setBuffer(kernel, def_k_d2mr_metrics, reduced.GetIndex())
|
| | | setArgument(kernel, def_k_d2mr_batch_count, (int)batches)
|
| | | setArgument(kernel, def_k_d2mr_input_count, (int)input_count)
|
| | | setArgument(kernel, def_k_d2mr_fields, (int)fields)
|
| | | setArgument(kernel, def_k_d2mr_input_offset, (int)input_offset)
|
| | | setArgument(kernel, def_k_d2mr_output_offset, (int)output_offset)
|
| | | setArgument(kernel, def_k_d2mr_max_field_a, max_field_a)
|
| | | setArgument(kernel, def_k_d2mr_max_field_b, max_field_b)
|
| | | setArgument(kernel, def_k_d2mr_final_output, final_output)
|
| | | const ulong active = (ulong)batches * output_count * fields;
|
2026-08-22 20:08:02 +03:00 | | | if(active == 0 || active > UINT_MAX)
|
| | | ReturnFalse;
|
| | | const uint stage_local_size = D2LaunchLocalSize((uint)active);
|
| | | if(stage_local_size == 0)
|
| | | ReturnFalse;
|
| | | const ulong padded = ((active + stage_local_size - 1) / stage_local_size) * stage_local_size;
|
| | | if(padded > UINT_MAX)
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
| | | uint global[1] = {(uint)padded};
|
2026-08-22 20:08:02 +03:00 | | | uint local[1] = {stage_local_size};
|
2026-08-20 19:55:53 +03:00 | | | kernelExecuteLoc(kernel, offset, global, local)
|
| | | if(final_output != 0)
|
| | | break;
|
| | | input_count = output_count;
|
| | | input_offset = output_offset;
|
| | | output_offset += batches * output_count * fields;
|
| | | }
|
| | | return(true);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Copies the source into the partials buffer, then runs the staged |
|
| | | //| reduction. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-27 11:39:46 +03:00 | | | bool CD2SkillBank::RunStagedReduction(CBufferFloat &source, CBufferFloat &partials,
|
| | | CBufferFloat &reduced, const uint items,
|
| | | const uint batches, const uint fields,
|
| | | const uint local_size, const int max_field_a,
|
| | | const int max_field_b)
|
| | | {
|
| | | if(!OpenCL || items == 0 || source.GetOpenCL() != OpenCL ||
|
| | | source.GetIndex() < 0 || source.Total() != (int)items)
|
| | | ReturnFalse;
|
| | | if(source.GetIndex() != partials.GetIndex())
|
| | | {
|
| | | uint offset[1] = {0};
|
| | | uint global[1] = {items};
|
| | | setBuffer(def_k_CopyBufferRaw, def_k_copy_raw_source, source.GetIndex())
|
| | | setBuffer(def_k_CopyBufferRaw, def_k_copy_raw_destination, partials.GetIndex())
|
| | | setArgument(def_k_CopyBufferRaw, def_k_copy_raw_total, (int)items)
|
| | | kernelExecute(def_k_CopyBufferRaw, offset, global)
|
| | | }
|
| | | return(RunStagedReduction(partials, reduced, items, batches, fields,
|
| | | local_size, max_field_a, max_field_b));
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Allocates all retrieval-stage scratch buffers. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-18 19:58:41 +03:00 | | | bool CD2SkillBank::EnsureRetrievalScratch(void)
|
| | | {
|
| | | uint local_size = 0;
|
| | | uint partial_count = 0;
|
2026-08-20 19:55:53 +03:00 | | | uint score_scratch = 0;
|
| | | if(!RetrievalLaunchLayout(local_size, partial_count) || partial_count > INT_MAX / 2 ||
|
| | | !ReductionScratchCount(m_dimension, m_slots, 4, score_scratch) ||
|
| | | m_slots > INT_MAX / 4)
|
| | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | const int pairs = (int)(2 * partial_count);
|
| | | return(EnsureRetrievalBuffer(m_retrieval_scores, (int)m_slots) &&
|
2026-08-20 19:55:53 +03:00 | | | EnsureRetrievalBuffer(m_score_partials, (int)score_scratch) &&
|
| | | EnsureRetrievalBuffer(m_score_metrics, (int)(4 * m_slots)) &&
|
2026-08-18 19:58:41 +03:00 | | | EnsureRetrievalBuffer(m_retrieval_partial, pairs) &&
|
2026-08-20 19:55:53 +03:00 | | | EnsureRetrievalBuffer(m_retrieval_merge, pairs) &&
|
| | | EnsureRetrievalBuffer(m_retrieval_top, 2));
|
2026-08-18 19:58:41 +03:00 | | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Computes the GPU launch layout for the bank update stage. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-18 19:58:41 +03:00 | | | bool CD2SkillBank::UpdateLaunchLayout(uint &local_size, uint &groups) const
|
| | | {
|
| | | if(!OpenCL || m_dimension == 0)
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
| | | uint limit = (uint)MathMin(OpenCL.GetMaxWorkGroupSize(), OpenCL.GetMaxLocalSize(0));
|
2026-08-18 19:58:41 +03:00 | | | if(limit == 0)
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | local_size = 1;
|
| | | while(local_size <= limit / 2)
|
| | | local_size *= 2;
|
| | | groups = (m_dimension + local_size - 1) / local_size;
|
| | | return(groups > 0);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Allocates all update-stage scratch buffers. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-18 19:58:41 +03:00 | | | bool CD2SkillBank::EnsureUpdateScratch(void)
|
| | | {
|
| | | uint local_size = 0;
|
| | | uint groups = 0;
|
2026-08-20 19:55:53 +03:00 | | | uint metric_scratch = 0;
|
| | | uint diagnostic_norm_scratch = 0;
|
| | | uint diagnostic_scratch = 0;
|
| | | uint influence_scratch = 0;
|
2026-08-20 22:59:48 +03:00 | | | uint gradient_influence_scratch = 0;
|
2026-08-20 19:55:53 +03:00 | | | if(!UpdateLaunchLayout(local_size, groups) ||
|
| | | !ReductionScratchCount(m_dimension, 1, D2SKILL_METRICS, metric_scratch) ||
|
| | | !ReductionScratchCount(m_dimension, m_slots, 1, diagnostic_norm_scratch) ||
|
| | | !ReductionScratchCount(m_slots, 1, D2SKILL_DIAGNOSTIC_PARTIALS, diagnostic_scratch) ||
|
2026-08-20 22:59:48 +03:00 | | | !ReductionScratchCount(m_slots, 1, 1, influence_scratch) ||
|
| | | !ReductionScratchCount(m_dimension, 1, 1, gradient_influence_scratch))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | return(EnsureRetrievalBuffer(m_free_scores, (int)m_slots) &&
|
| | | EnsureRetrievalBuffer(m_eviction_scores, (int)m_slots) &&
|
| | | EnsureRetrievalBuffer(m_free_top, 2) && EnsureRetrievalBuffer(m_eviction_top, 2) &&
|
2026-08-20 19:55:53 +03:00 | | | EnsureRetrievalBuffer(m_metric_partials, (int)metric_scratch) &&
|
2026-08-18 19:58:41 +03:00 | | | EnsureRetrievalBuffer(m_metrics, D2SKILL_METRICS) &&
|
| | | EnsureRetrievalBuffer(m_decision, 4) &&
|
2026-08-20 19:55:53 +03:00 | | | EnsureRetrievalBuffer(m_diagnostics_norm_partials, (int)diagnostic_norm_scratch) &&
|
| | | EnsureRetrievalBuffer(m_diagnostics_norms, (int)m_slots) &&
|
| | | EnsureRetrievalBuffer(m_diagnostics_partials, (int)diagnostic_scratch) &&
|
| | | EnsureRetrievalBuffer(m_diagnostics_totals, D2SKILL_DIAGNOSTIC_PARTIALS) &&
|
2026-08-20 22:59:48 +03:00 | | | EnsureRetrievalBuffer(m_influence_partials, (int)influence_scratch) &&
|
| | | EnsureRetrievalBuffer(m_gradient_influence_partials, (int)gradient_influence_scratch) &&
|
| | | EnsureRetrievalBuffer(m_gradient_influence_total, 1));
|
2026-08-18 19:58:41 +03:00 | | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Finds the best scoring slot using the generic RAG Top-1 |
|
| | | //| partial/merge kernels. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-18 19:58:41 +03:00 | | | bool CD2SkillBank::RunTop1(CBufferFloat &scores, CBufferFloat &top)
|
| | | {
|
| | | uint local_size = 0;
|
| | | uint partial_count = 0;
|
| | | if(!RetrievalLaunchLayout(local_size, partial_count) || !EnsureRetrievalScratch())
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | uint offset[1] = {0};
|
| | | const uint block_size = RAG_TOPK_LOCAL_WIDTH;
|
| | | const int partial_kernel = def_k_RAGPartial;
|
| | | setBuffer(partial_kernel, def_k_ragp_scores, scores.GetIndex())
|
| | | setBuffer(partial_kernel, def_k_ragp_partial, m_retrieval_partial.GetIndex())
|
| | | setArgument(partial_kernel, def_k_ragp_scenario_count, (int)m_slots)
|
| | | setArgument(partial_kernel, def_k_ragp_block_size, (int)block_size)
|
| | | setArgument(partial_kernel, def_k_ragp_top_k, 1)
|
| | | uint partial_global[1] = {partial_count * block_size};
|
| | | uint partial_local[1] = {block_size};
|
| | | kernelExecuteLoc(partial_kernel, offset, partial_global, partial_local)
|
| | | uint count = partial_count;
|
| | | CBufferFloat *source = GetPointer(m_retrieval_partial);
|
| | | CBufferFloat *destination = GetPointer(m_retrieval_merge);
|
| | | const int merge_kernel = def_k_RAGMerge;
|
| | | while(count > block_size)
|
| | | {
|
| | | const uint blocks = (count + block_size - 1) / block_size;
|
| | | setBuffer(merge_kernel, def_k_ragm_source, source.GetIndex())
|
| | | setBuffer(merge_kernel, def_k_ragm_destination, destination.GetIndex())
|
| | | setArgument(merge_kernel, def_k_ragm_candidate_count, (int)count)
|
| | | setArgument(merge_kernel, def_k_ragm_block_size, (int)block_size)
|
| | | setArgument(merge_kernel, def_k_ragm_top_k, 1)
|
| | | uint global[1] = {blocks * block_size};
|
| | | uint local[1] = {block_size};
|
| | | kernelExecuteLoc(merge_kernel, offset, global, local)
|
| | | count = blocks;
|
| | | CBufferFloat *swap = source;
|
| | | source = destination;
|
| | | destination = swap;
|
| | | }
|
| | | setBuffer(merge_kernel, def_k_ragm_source, source.GetIndex())
|
| | | setBuffer(merge_kernel, def_k_ragm_destination, top.GetIndex())
|
| | | setArgument(merge_kernel, def_k_ragm_candidate_count, (int)count)
|
| | | setArgument(merge_kernel, def_k_ragm_block_size, (int)block_size)
|
| | | setArgument(merge_kernel, def_k_ragm_top_k, 1)
|
| | | uint global[1] = {block_size};
|
| | | uint local[1] = {block_size};
|
| | | kernelExecuteLoc(merge_kernel, offset, global, local)
|
| | | return(true);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Computes the per-slot metrics for the given state and gradient. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-18 19:58:41 +03:00 | | | bool CD2SkillBank::RunMetrics(CBufferFloat *state, CBufferFloat *gradient,
|
| | | const uint local_size, const uint groups)
|
| | | {
|
| | | if(!state || !gradient)
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | uint offset[1] = {0};
|
| | | const int partial_kernel = def_k_D2SkillMetricPartial;
|
| | | setBuffer(partial_kernel, def_k_d2mp_query, state.GetIndex())
|
| | | setBuffer(partial_kernel, def_k_d2mp_gradient, gradient.GetIndex())
|
| | | setBuffer(partial_kernel, def_k_d2mp_selected_slot, m_selected_slot.GetIndex())
|
| | | setBuffer(partial_kernel, def_k_d2mp_keys, m_keys.GetIndex())
|
| | | setBuffer(partial_kernel, def_k_d2mp_directions, m_directions.GetIndex())
|
| | | setBuffer(partial_kernel, def_k_d2mp_used, m_used.GetIndex())
|
2026-08-20 19:55:53 +03:00 | | | setBuffer(partial_kernel, def_k_d2mp_candidate_top, m_retrieval_top.GetIndex())
|
| | | setBuffer(partial_kernel, def_k_d2mp_candidate_key, m_keys.GetIndex())
|
| | | setBuffer(partial_kernel, def_k_d2mp_candidate_direction, m_directions.GetIndex())
|
2026-08-18 19:58:41 +03:00 | | | setBuffer(partial_kernel, def_k_d2mp_partials, m_metric_partials.GetIndex())
|
| | | setArgument(partial_kernel, def_k_d2mp_slots, (int)m_slots)
|
| | | setArgument(partial_kernel, def_k_d2mp_dimension, (int)m_dimension)
|
| | | uint partial_global[1] = {groups * local_size};
|
| | | uint partial_local[1] = {local_size};
|
| | | kernelExecuteLoc(partial_kernel, offset, partial_global, partial_local)
|
2026-08-20 19:55:53 +03:00 | | | return(RunStagedReduction(m_metric_partials, m_metrics, m_dimension, 1,
|
| | | D2SKILL_METRICS, local_size));
|
2026-08-18 19:58:41 +03:00 | | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Computes the bank vector norm for the active representation. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-18 19:58:41 +03:00 | | | bool CD2SkillBank::CalculateBankVectorNorm(const uint local_size, const uint groups)
|
| | | {
|
| | | if(local_size == 0 || groups == 0 || !EnsureItemScratch())
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | uint offset[1] = {0};
|
| | | const int partial_kernel = def_k_D2SkillBankVectorPartial;
|
| | | setBuffer(partial_kernel, def_k_d2bvp_corrections, m_corrections.GetIndex())
|
| | | setBuffer(partial_kernel, def_k_d2bvp_directions, m_directions.GetIndex())
|
| | | setBuffer(partial_kernel, def_k_d2bvp_decision, m_decision.GetIndex())
|
| | | setBuffer(partial_kernel, def_k_d2bvp_partials, m_item_partials.GetIndex())
|
| | | setArgument(partial_kernel, def_k_d2bvp_dimension, (int)m_dimension)
|
| | | setArgument(partial_kernel, def_k_d2bvp_representation, (int)m_representation)
|
| | | setArgument(partial_kernel, def_k_d2bvp_output_offset, 0)
|
| | | uint partial_global[1] = {groups * local_size};
|
| | | uint partial_local[1] = {local_size};
|
| | | kernelExecuteLoc(partial_kernel, offset, partial_global, partial_local)
|
2026-08-20 19:55:53 +03:00 | | | //--- The item scratch is sized for the wider binary Item norm reduction, so it
|
| | | //--- also contains every radix-8 stage required for this one-field bank norm.
|
| | | return(RunStagedReduction(m_item_partials, m_item_reduced_norm, m_dimension,
|
| | | 1, 1, local_size));
|
2026-08-18 19:58:41 +03:00 | | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Initializes the bank with the given slot count and dimension, |
|
| | | //| allocating every GPU buffer. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-18 19:58:41 +03:00 | | | bool CD2SkillBank::Init(uint dimension, uint myIndex, COpenCLMy *open_cl,
|
| | | uint slots, ENUM_OPTIMIZATION optimization_type, uint batch)
|
| | | {
|
| | | if(!open_cl || dimension == 0 || slots == 0 || slots > RAG_FLOAT_INDEX_LIMIT ||
|
| | | !CD2SkillItem::Init(0, myIndex, open_cl, dimension, optimization_type, batch))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | m_dimension = dimension;
|
| | | m_slots = slots;
|
| | | m_active_slot = UINT_MAX;
|
| | | const long total = (long)m_slots * (long)m_dimension;
|
| | | if(total <= 0 || total > 2147483647)
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | if(!InitBuffer(m_keys, (int)total) || !InitBuffer(m_corrections, (int)total) ||
|
| | | !InitBuffer(m_directions, (int)total) || !InitBuffer(m_scales, (int)m_slots) ||
|
| | | !InitBuffer(m_utility, (int)m_slots) || !InitBuffer(m_observations, (int)m_slots) ||
|
| | | !InitBuffer(m_uses, (int)m_slots) || !InitBuffer(m_mass, (int)m_slots) ||
|
| | | !InitBuffer(m_used, (int)m_slots) || !InitBuffer(m_state, (int)m_slots) ||
|
| | | !InitBuffer(m_age, (int)m_slots) || !InitBuffer(m_protection, (int)m_slots) ||
|
2026-08-27 11:39:46 +03:00 | | | !InitBuffer(m_influence, (int)m_slots) || !InitBuffer(m_utility_applied, (int)m_slots) ||
|
| | | !InitBuffer(m_influence_total, 1) ||
|
2026-08-20 22:59:48 +03:00 | | | !InitBuffer(m_gradient_influence_total, 1) ||
|
2026-08-20 19:55:53 +03:00 | | | !InitBuffer(m_retrieved, (int)m_slots) ||
|
2026-08-18 19:58:41 +03:00 | | | !InitBuffer(m_selected_correction, (int)m_dimension) ||
|
| | | !InitBuffer(m_selected_slot, 1, -1.0f) ||
|
| | | !InitBuffer(m_selected_score, 1, -3.402823e+38f) ||
|
| | | !InitBuffer(m_diagnostics, D2SKILL_DIAGNOSTICS) ||
|
| | | !InitBuffer(m_utility_distribution, D2SKILL_DISTRIBUTION_BINS) ||
|
| | | !InitBuffer(m_usage_distribution, D2SKILL_DISTRIBUTION_BINS) ||
|
| | | !EnsureRetrievalScratch() || !EnsureUpdateScratch())
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | if(!SetCorrectionBuffer(GetPointer(m_selected_correction)))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | return(true);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Rebinds every bank GPU buffer to the given OpenCL context and |
|
| | | //| re-exposes the selected correction. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-18 19:58:41 +03:00 | | | void CD2SkillBank::SetOpenCL(COpenCLMy *obj)
|
| | | {
|
| | | CD2SkillItem::SetOpenCL(obj);
|
| | | RebindBuffer(m_keys, obj);
|
| | | RebindBuffer(m_corrections, obj);
|
| | | RebindBuffer(m_directions, obj);
|
| | | RebindBuffer(m_scales, obj);
|
| | | RebindBuffer(m_utility, obj);
|
| | | RebindBuffer(m_observations, obj);
|
| | | RebindBuffer(m_uses, obj);
|
| | | RebindBuffer(m_mass, obj);
|
| | | RebindBuffer(m_used, obj);
|
| | | RebindBuffer(m_state, obj);
|
| | | RebindBuffer(m_age, obj);
|
| | | RebindBuffer(m_protection, obj);
|
2026-08-20 19:55:53 +03:00 | | | RebindBuffer(m_influence, obj);
|
2026-08-27 11:39:46 +03:00 | | | RebindBuffer(m_utility_applied, obj);
|
2026-08-20 19:55:53 +03:00 | | | RebindBuffer(m_influence_total, obj);
|
| | | RebindBuffer(m_influence_partials, obj);
|
2026-08-20 22:59:48 +03:00 | | | RebindBuffer(m_gradient_influence_total, obj);
|
| | | RebindBuffer(m_gradient_influence_partials, obj);
|
2026-08-20 19:55:53 +03:00 | | | RebindBuffer(m_retrieved, obj);
|
2026-08-18 19:58:41 +03:00 | | | RebindBuffer(m_selected_correction, obj);
|
| | | RebindBuffer(m_selected_slot, obj);
|
| | | RebindBuffer(m_selected_score, obj);
|
| | | RebindBuffer(m_diagnostics, obj);
|
| | | RebindBuffer(m_utility_distribution, obj);
|
| | | RebindBuffer(m_usage_distribution, obj);
|
2026-08-20 19:55:53 +03:00 | | | RebindBuffer(m_retrieval_scores, obj);
|
| | | RebindBuffer(m_score_partials, obj);
|
| | | RebindBuffer(m_score_metrics, obj);
|
| | | RebindBuffer(m_retrieval_partial, obj);
|
| | | RebindBuffer(m_retrieval_merge, obj);
|
| | | RebindBuffer(m_retrieval_top, obj);
|
2026-08-18 19:58:41 +03:00 | | | RebindBuffer(m_free_scores, obj);
|
| | | RebindBuffer(m_eviction_scores, obj);
|
| | | RebindBuffer(m_free_top, obj);
|
| | | RebindBuffer(m_eviction_top, obj);
|
| | | RebindBuffer(m_metric_partials, obj);
|
| | | RebindBuffer(m_metrics, obj);
|
| | | RebindBuffer(m_decision, obj);
|
2026-08-20 19:55:53 +03:00 | | | RebindBuffer(m_diagnostics_norm_partials, obj);
|
| | | RebindBuffer(m_diagnostics_norms, obj);
|
2026-08-18 19:58:41 +03:00 | | | RebindBuffer(m_diagnostics_partials, obj);
|
2026-08-20 19:55:53 +03:00 | | | RebindBuffer(m_diagnostics_totals, obj);
|
2026-08-18 19:58:41 +03:00 | | | EnsureRetrievalScratch();
|
| | | EnsureUpdateScratch();
|
2026-08-20 19:55:53 +03:00 | | | //--- CD2SkillItem::SetOpenCL binds its standalone correction buffer.
|
| | | //--- A bank must instead expose its selected slot correction to the item.
|
| | | if(m_selected_correction.Total() == (int)m_dimension &&
|
| | | m_selected_correction.GetOpenCL() == obj && m_selected_correction.GetIndex() >= 0)
|
| | | m_correction = GetPointer(m_selected_correction);
|
2026-08-18 19:58:41 +03:00 | | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-14 09:56:18 +03:00 | | | //| Reports checked transfer support for an exact D2 skill bank. |
|
| | | //+------------------------------------------------------------------+
|
| | | bool CD2SkillBank::SupportsOpenCLChecked(void) const
|
| | | {
|
| | | return(Type() == defNeuronD2SkillBank && ValidateBankOwnedCheckedState(false));
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
| | | //| Checks strict Bank transfer support for a specific target. |
|
| | | //+------------------------------------------------------------------+
|
| | | bool CD2SkillBank::SupportsOpenCLChecked(const COpenCLMy *target) const
|
| | | {
|
| | | return(Type() == defNeuronD2SkillBank &&
|
| | | ValidateBankOwnedCheckedState(false, target));
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
| | | //| Validates the Bank-owned checked state before any mutation. |
|
| | | //+------------------------------------------------------------------+
|
| | | bool CD2SkillBank::ValidateBankOwnedCheckedState(const bool allow_missing_transient,
|
| | | const COpenCLMy *target) const
|
| | | {
|
| | | //--- Validate fixed geometry before deriving any scratch-buffer sizes.
|
| | | if(!ValidateItemOwnedCheckedState(allow_missing_transient) ||
|
| | | m_slots == 0 || m_dimension == 0 || m_dimension != m_item_dimension ||
|
| | | m_slots > RAG_FLOAT_INDEX_LIMIT)
|
| | | return(false);
|
| | |
|
| | | const long vector_total = (long)m_slots * (long)m_dimension;
|
| | | if(vector_total <= 0 || vector_total > INT_MAX || m_slots > (uint)INT_MAX ||
|
| | | m_slots > (uint)INT_MAX / 4)
|
| | | return(false);
|
| | |
|
| | | //--- Derive every existing scratch size without allocation or mutable validation.
|
| | | uint retrieval_local = 0;
|
| | | uint retrieval_partials = 0;
|
| | | uint score_partials = 0;
|
| | | uint metric_partials = 0;
|
| | | uint diagnostics_norm_partials = 0;
|
| | | uint diagnostics_partials = 0;
|
| | | uint influence_partials = 0;
|
| | | uint gradient_influence_partials = 0;
|
| | | if(!RetrievalLaunchLayout(retrieval_local, retrieval_partials) ||
|
| | | retrieval_partials > (uint)INT_MAX / 2 ||
|
| | | !ReductionScratchCount(m_dimension, m_slots, 4, score_partials) ||
|
| | | !ReductionScratchCount(m_dimension, 1, D2SKILL_METRICS, metric_partials) ||
|
| | | !ReductionScratchCount(m_dimension, m_slots, 1, diagnostics_norm_partials) ||
|
| | | !ReductionScratchCount(m_slots, 1, D2SKILL_DIAGNOSTIC_PARTIALS, diagnostics_partials) ||
|
| | | !ReductionScratchCount(m_slots, 1, 1, influence_partials) ||
|
| | | !ReductionScratchCount(m_dimension, 1, 1, gradient_influence_partials) ||
|
| | | score_partials > (uint)INT_MAX || metric_partials > (uint)INT_MAX ||
|
| | | diagnostics_norm_partials > (uint)INT_MAX || diagnostics_partials > (uint)INT_MAX ||
|
| | | influence_partials > (uint)INT_MAX || gradient_influence_partials > (uint)INT_MAX)
|
| | | return(false);
|
| | |
|
| | | //--- Map all Bank-owned slots to their established host shapes.
|
| | | const CBufferFloat *buffers[42];
|
| | | int totals[42];
|
| | | buffers[0] = GetPointer(m_keys);
|
| | | totals[0] = (int)vector_total;
|
| | | buffers[1] = GetPointer(m_corrections);
|
| | | totals[1] = (int)vector_total;
|
| | | buffers[2] = GetPointer(m_directions);
|
| | | totals[2] = (int)vector_total;
|
| | | buffers[3] = GetPointer(m_scales);
|
| | | totals[3] = (int)m_slots;
|
| | | buffers[4] = GetPointer(m_utility);
|
| | | totals[4] = (int)m_slots;
|
| | | buffers[5] = GetPointer(m_observations);
|
| | | totals[5] = (int)m_slots;
|
| | | buffers[6] = GetPointer(m_uses);
|
| | | totals[6] = (int)m_slots;
|
| | | buffers[7] = GetPointer(m_mass);
|
| | | totals[7] = (int)m_slots;
|
| | | buffers[8] = GetPointer(m_used);
|
| | | totals[8] = (int)m_slots;
|
| | | buffers[9] = GetPointer(m_state);
|
| | | totals[9] = (int)m_slots;
|
| | | buffers[10] = GetPointer(m_age);
|
| | | totals[10] = (int)m_slots;
|
| | | buffers[11] = GetPointer(m_protection);
|
| | | totals[11] = (int)m_slots;
|
| | | buffers[12] = GetPointer(m_influence);
|
| | | totals[12] = (int)m_slots;
|
| | | buffers[13] = GetPointer(m_utility_applied);
|
| | | totals[13] = (int)m_slots;
|
| | | buffers[14] = GetPointer(m_retrieved);
|
| | | totals[14] = (int)m_slots;
|
| | | buffers[15] = GetPointer(m_retrieval_scores);
|
| | | totals[15] = (int)m_slots;
|
| | | buffers[16] = GetPointer(m_free_scores);
|
| | | totals[16] = (int)m_slots;
|
| | | buffers[17] = GetPointer(m_eviction_scores);
|
| | | totals[17] = (int)m_slots;
|
| | | buffers[18] = GetPointer(m_diagnostics_norms);
|
| | | totals[18] = (int)m_slots;
|
| | | buffers[19] = GetPointer(m_influence_total);
|
| | | totals[19] = 1;
|
| | | buffers[20] = GetPointer(m_gradient_influence_total);
|
| | | totals[20] = 1;
|
| | | buffers[21] = GetPointer(m_selected_slot);
|
| | | totals[21] = 1;
|
| | | buffers[22] = GetPointer(m_selected_score);
|
| | | totals[22] = 1;
|
| | | buffers[23] = GetPointer(m_selected_correction);
|
| | | totals[23] = (int)m_dimension;
|
| | | buffers[24] = GetPointer(m_diagnostics);
|
| | | totals[24] = D2SKILL_DIAGNOSTICS;
|
| | | buffers[25] = GetPointer(m_utility_distribution);
|
| | | totals[25] = D2SKILL_DISTRIBUTION_BINS;
|
| | | buffers[26] = GetPointer(m_usage_distribution);
|
| | | totals[26] = D2SKILL_DISTRIBUTION_BINS;
|
| | | buffers[27] = GetPointer(m_score_partials);
|
| | | totals[27] = (int)score_partials;
|
| | | buffers[28] = GetPointer(m_score_metrics);
|
| | | totals[28] = (int)(4 * m_slots);
|
| | | buffers[29] = GetPointer(m_retrieval_partial);
|
| | | totals[29] = (int)(2 * retrieval_partials);
|
| | | buffers[30] = GetPointer(m_retrieval_merge);
|
| | | totals[30] = (int)(2 * retrieval_partials);
|
| | | buffers[31] = GetPointer(m_retrieval_top);
|
| | | totals[31] = 2;
|
| | | buffers[32] = GetPointer(m_free_top);
|
| | | totals[32] = 2;
|
| | | buffers[33] = GetPointer(m_eviction_top);
|
| | | totals[33] = 2;
|
| | | buffers[34] = GetPointer(m_metric_partials);
|
| | | totals[34] = (int)metric_partials;
|
| | | buffers[35] = GetPointer(m_metrics);
|
| | | totals[35] = D2SKILL_METRICS;
|
| | | buffers[36] = GetPointer(m_decision);
|
| | | totals[36] = 4;
|
| | | buffers[37] = GetPointer(m_diagnostics_norm_partials);
|
| | | totals[37] = (int)diagnostics_norm_partials;
|
| | | buffers[38] = GetPointer(m_diagnostics_partials);
|
| | | totals[38] = (int)diagnostics_partials;
|
| | | buffers[39] = GetPointer(m_diagnostics_totals);
|
| | | totals[39] = D2SKILL_DIAGNOSTIC_PARTIALS;
|
| | | buffers[40] = GetPointer(m_influence_partials);
|
| | | totals[40] = (int)influence_partials;
|
| | | buffers[41] = GetPointer(m_gradient_influence_partials);
|
| | | totals[41] = (int)gradient_influence_partials;
|
| | |
|
| | | //--- Deferred loads may omit only transient slots; every present slot keeps its shape and owner.
|
| | | for(int i = 0; i < 42; i++)
|
| | | {
|
| | | const bool transient = (i >= 13 && i <= 20) || i >= 27;
|
| | | const bool absent = buffers[i].Total() == 0 && buffers[i].GetIndex() < 0;
|
| | | if(CheckPointer(buffers[i]) == POINTER_INVALID ||
|
| | | (buffers[i].Total() != totals[i] &&
|
| | | (!allow_missing_transient || !transient || !absent)) ||
|
| | | (buffers[i].GetIndex() >= 0 &&
|
| | | CheckPointer(buffers[i].GetOpenCL()) == POINTER_INVALID))
|
| | | return(false);
|
| | | }
|
| | |
|
| | | //--- Only Item and selected-Bank aliases may remain host-only for checked repair.
|
| | | if(m_correction != NULL && m_correction != GetPointer(m_item_correction) &&
|
| | | m_correction != GetPointer(m_selected_correction) &&
|
| | | (CheckPointer(m_correction) == POINTER_INVALID ||
|
| | | m_correction.Total() != (int)m_dimension || m_correction.GetIndex() < 0 ||
|
| | | CheckPointer(m_correction.GetOpenCL()) == POINTER_INVALID ||
|
| | | (target != NULL && m_correction.GetOpenCL() != target)))
|
| | | return(false);
|
| | |
|
| | | //--- Finalize exact Bank capability after every owned slot is checked.
|
| | | return(true);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
| | | //| Checks a loaded Bank before its missing transient slots exist. |
|
| | | //+------------------------------------------------------------------+
|
| | | bool CD2SkillBank::SupportsDeferredOpenCLChecked(const COpenCLMy *target) const
|
| | | {
|
| | | return(Type() == defNeuronD2SkillBank &&
|
| | | ValidateBankOwnedCheckedState(true, target));
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
| | | //| Initializes absent loaded-bank transient host slots only. |
|
| | | //+------------------------------------------------------------------+
|
| | | bool CD2SkillBank::PrepareOpenCLChecked(COpenCLMy *target)
|
| | | {
|
| | | //--- Complete target-aware prevalidation before any host-only slot is initialized.
|
| | | if(!SupportsDeferredOpenCLChecked(target))
|
| | | return(false);
|
| | | if(!PrepareItemOwnedCheckedState())
|
| | | return(false);
|
| | |
|
| | | //--- Derive every transient host-buffer shape without allocating device storage.
|
| | | uint retrieval_local = 0;
|
| | | uint retrieval_partials = 0;
|
| | | uint score_partials = 0;
|
| | | uint metric_partials = 0;
|
| | | uint diagnostic_norm_partials = 0;
|
| | | uint diagnostic_partials = 0;
|
| | | uint influence_partials = 0;
|
| | | uint gradient_influence_partials = 0;
|
| | | if(!RetrievalLaunchLayout(retrieval_local, retrieval_partials))
|
| | | ReturnFalseEx("bank retrieval launch layout");
|
| | | if(!ReductionScratchCount(m_dimension, m_slots, 4, score_partials))
|
| | | ReturnFalseEx("bank score partials shape");
|
| | | if(!ReductionScratchCount(m_dimension, 1, D2SKILL_METRICS, metric_partials))
|
| | | ReturnFalseEx("bank metric partials shape");
|
| | | if(!ReductionScratchCount(m_dimension, m_slots, 1, diagnostic_norm_partials))
|
| | | ReturnFalseEx("bank diagnostic norm partials shape");
|
| | | if(!ReductionScratchCount(m_slots, 1, D2SKILL_DIAGNOSTIC_PARTIALS, diagnostic_partials))
|
| | | ReturnFalseEx("bank diagnostic partials shape");
|
| | | if(!ReductionScratchCount(m_slots, 1, 1, influence_partials))
|
| | | ReturnFalseEx("bank influence partials shape");
|
| | | if(!ReductionScratchCount(m_dimension, 1, 1, gradient_influence_partials))
|
| | | ReturnFalseEx("bank gradient influence partials shape");
|
| | |
|
| | | //--- Map transient Bank slots to their established host shapes.
|
| | | CBufferFloat *buffers[23];
|
| | | int totals[23];
|
| | | string slots[23] = {"utility applied", "influence total",
|
| | | "gradient influence total", "retrieved", "retrieval scores",
|
| | | "free scores", "eviction scores", "diagnostic norms",
|
| | | "score partials", "score metrics", "retrieval partial",
|
| | | "retrieval merge", "retrieval top", "free top", "eviction top",
|
| | | "metric partials", "metrics", "decision",
|
| | | "diagnostic norm partials", "diagnostic partials",
|
| | | "diagnostic totals", "influence partials",
|
| | | "gradient influence partials"};
|
| | | buffers[0] = GetPointer(m_utility_applied);
|
| | | totals[0] = (int)m_slots;
|
| | | buffers[1] = GetPointer(m_influence_total);
|
| | | totals[1] = 1;
|
| | | buffers[2] = GetPointer(m_gradient_influence_total);
|
| | | totals[2] = 1;
|
| | | buffers[3] = GetPointer(m_retrieved);
|
| | | totals[3] = (int)m_slots;
|
| | | buffers[4] = GetPointer(m_retrieval_scores);
|
| | | totals[4] = (int)m_slots;
|
| | | buffers[5] = GetPointer(m_free_scores);
|
| | | totals[5] = (int)m_slots;
|
| | | buffers[6] = GetPointer(m_eviction_scores);
|
| | | totals[6] = (int)m_slots;
|
| | | buffers[7] = GetPointer(m_diagnostics_norms);
|
| | | totals[7] = (int)m_slots;
|
| | | buffers[8] = GetPointer(m_score_partials);
|
| | | totals[8] = (int)score_partials;
|
| | | buffers[9] = GetPointer(m_score_metrics);
|
| | | totals[9] = (int)(4 * m_slots);
|
| | | buffers[10] = GetPointer(m_retrieval_partial);
|
| | | totals[10] = (int)(2 * retrieval_partials);
|
| | | buffers[11] = GetPointer(m_retrieval_merge);
|
| | | totals[11] = (int)(2 * retrieval_partials);
|
| | | buffers[12] = GetPointer(m_retrieval_top);
|
| | | totals[12] = 2;
|
| | | buffers[13] = GetPointer(m_free_top);
|
| | | totals[13] = 2;
|
| | | buffers[14] = GetPointer(m_eviction_top);
|
| | | totals[14] = 2;
|
| | | buffers[15] = GetPointer(m_metric_partials);
|
| | | totals[15] = (int)metric_partials;
|
| | | buffers[16] = GetPointer(m_metrics);
|
| | | totals[16] = D2SKILL_METRICS;
|
| | | buffers[17] = GetPointer(m_decision);
|
| | | totals[17] = 4;
|
| | | buffers[18] = GetPointer(m_diagnostics_norm_partials);
|
| | | totals[18] = (int)diagnostic_norm_partials;
|
| | | buffers[19] = GetPointer(m_diagnostics_partials);
|
| | | totals[19] = (int)diagnostic_partials;
|
| | | buffers[20] = GetPointer(m_diagnostics_totals);
|
| | | totals[20] = D2SKILL_DIAGNOSTIC_PARTIALS;
|
| | | buffers[21] = GetPointer(m_influence_partials);
|
| | | totals[21] = (int)influence_partials;
|
| | | buffers[22] = GetPointer(m_gradient_influence_partials);
|
| | | totals[22] = (int)gradient_influence_partials;
|
| | |
|
| | | //--- Reject malformed optional slots before initializing only their absent host mirrors.
|
| | | for(int i = 0; i < 23; i++)
|
| | | if(CheckPointer(buffers[i]) == POINTER_INVALID ||
|
| | | (buffers[i].Total() != totals[i] &&
|
| | | (buffers[i].Total() != 0 || buffers[i].GetIndex() >= 0)) ||
|
| | | (buffers[i].GetIndex() >= 0 &&
|
| | | CheckPointer(buffers[i].GetOpenCL()) == POINTER_INVALID))
|
| | | ReturnFalseEx("bank " + slots[i] + " checked state");
|
| | |
|
| | | //--- Initialize only the accepted unallocated transient buffers on the CPU.
|
| | | for(int i = 0; i < 23; i++)
|
| | | if(buffers[i].Total() == 0 && !buffers[i].BufferInit(totals[i], 0.0f))
|
| | | ReturnFalseEx("bank " + slots[i] + " host init");
|
| | |
|
| | | return(true);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
| | | //| Transfers all Bank buffers before the qualified Item transfer. |
|
| | | //+------------------------------------------------------------------+
|
| | | bool CD2SkillBank::SetOpenCLChecked(COpenCLMy *obj)
|
| | | {
|
| | | //--- Reject a foreign borrowed alias before any owned Bank mutation.
|
| | | if(CheckPointer(obj) == POINTER_INVALID || !SupportsOpenCLChecked())
|
| | | ReturnFalseEx("checked bank target or capability");
|
| | | if(m_correction != NULL && m_correction != GetPointer(m_item_correction) &&
|
| | | m_correction != GetPointer(m_selected_correction) &&
|
| | | (m_correction.GetOpenCL() != obj || m_correction.GetIndex() < 0 ||
|
| | | m_correction.Total() != (int)m_dimension ||
|
| | | CheckPointer(m_correction.GetOpenCL()) == POINTER_INVALID))
|
| | | ReturnFalseEx("borrowed bank correction target");
|
| | |
|
| | | //--- Read every foreign allocated Bank buffer before any Bank buffer is recreated.
|
| | | CBufferFloat *buffers[42];
|
| | | string labels[42];
|
| | | buffers[0] = GetPointer(m_keys);
|
| | | labels[0] = "bank keys";
|
| | | buffers[1] = GetPointer(m_corrections);
|
| | | labels[1] = "bank corrections";
|
| | | buffers[2] = GetPointer(m_directions);
|
| | | labels[2] = "bank directions";
|
| | | buffers[3] = GetPointer(m_scales);
|
| | | labels[3] = "bank scales";
|
| | | buffers[4] = GetPointer(m_utility);
|
| | | labels[4] = "bank utility";
|
| | | buffers[5] = GetPointer(m_observations);
|
| | | labels[5] = "bank observations";
|
| | | buffers[6] = GetPointer(m_uses);
|
| | | labels[6] = "bank uses";
|
| | | buffers[7] = GetPointer(m_mass);
|
| | | labels[7] = "bank mass";
|
| | | buffers[8] = GetPointer(m_used);
|
| | | labels[8] = "bank used";
|
| | | buffers[9] = GetPointer(m_state);
|
| | | labels[9] = "bank state";
|
| | | buffers[10] = GetPointer(m_age);
|
| | | labels[10] = "bank age";
|
| | | buffers[11] = GetPointer(m_protection);
|
| | | labels[11] = "bank protection";
|
| | | buffers[12] = GetPointer(m_influence);
|
| | | labels[12] = "bank influence";
|
| | | buffers[13] = GetPointer(m_utility_applied);
|
| | | labels[13] = "bank utility applied";
|
| | | buffers[14] = GetPointer(m_retrieved);
|
| | | labels[14] = "bank retrieved";
|
| | | buffers[15] = GetPointer(m_retrieval_scores);
|
| | | labels[15] = "bank retrieval scores";
|
| | | buffers[16] = GetPointer(m_free_scores);
|
| | | labels[16] = "bank free scores";
|
| | | buffers[17] = GetPointer(m_eviction_scores);
|
| | | labels[17] = "bank eviction scores";
|
| | | buffers[18] = GetPointer(m_diagnostics_norms);
|
| | | labels[18] = "bank diagnostics norms";
|
| | | buffers[19] = GetPointer(m_influence_total);
|
| | | labels[19] = "bank influence total";
|
| | | buffers[20] = GetPointer(m_gradient_influence_total);
|
| | | labels[20] = "bank gradient influence total";
|
| | | buffers[21] = GetPointer(m_selected_slot);
|
| | | labels[21] = "bank selected slot";
|
| | | buffers[22] = GetPointer(m_selected_score);
|
| | | labels[22] = "bank selected score";
|
| | | buffers[23] = GetPointer(m_selected_correction);
|
| | | labels[23] = "bank selected correction";
|
| | | buffers[24] = GetPointer(m_diagnostics);
|
| | | labels[24] = "bank diagnostics";
|
| | | buffers[25] = GetPointer(m_utility_distribution);
|
| | | labels[25] = "bank utility distribution";
|
| | | buffers[26] = GetPointer(m_usage_distribution);
|
| | | labels[26] = "bank usage distribution";
|
| | | buffers[27] = GetPointer(m_score_partials);
|
| | | labels[27] = "bank score partials";
|
| | | buffers[28] = GetPointer(m_score_metrics);
|
| | | labels[28] = "bank score metrics";
|
| | | buffers[29] = GetPointer(m_retrieval_partial);
|
| | | labels[29] = "bank retrieval partial";
|
| | | buffers[30] = GetPointer(m_retrieval_merge);
|
| | | labels[30] = "bank retrieval merge";
|
| | | buffers[31] = GetPointer(m_retrieval_top);
|
| | | labels[31] = "bank retrieval top";
|
| | | buffers[32] = GetPointer(m_free_top);
|
| | | labels[32] = "bank free top";
|
| | | buffers[33] = GetPointer(m_eviction_top);
|
| | | labels[33] = "bank eviction top";
|
| | | buffers[34] = GetPointer(m_metric_partials);
|
| | | labels[34] = "bank metric partials";
|
| | | buffers[35] = GetPointer(m_metrics);
|
| | | labels[35] = "bank metrics";
|
| | | buffers[36] = GetPointer(m_decision);
|
| | | labels[36] = "bank decision";
|
| | | buffers[37] = GetPointer(m_diagnostics_norm_partials);
|
| | | labels[37] = "bank diagnostics norm partials";
|
| | | buffers[38] = GetPointer(m_diagnostics_partials);
|
| | | labels[38] = "bank diagnostics partials";
|
| | | buffers[39] = GetPointer(m_diagnostics_totals);
|
| | | labels[39] = "bank diagnostics totals";
|
| | | buffers[40] = GetPointer(m_influence_partials);
|
| | | labels[40] = "bank influence partials";
|
| | | buffers[41] = GetPointer(m_gradient_influence_partials);
|
| | | labels[41] = "bank gradient influence partials";
|
| | |
|
| | | for(int i = 0; i < 42; i++)
|
| | | {
|
| | | if(buffers[i].GetIndex() >= 0 &&
|
| | | CheckPointer(buffers[i].GetOpenCL()) == POINTER_INVALID)
|
| | | ReturnFalseEx(labels[i] + " owner");
|
| | | if(buffers[i].GetIndex() >= 0 && buffers[i].GetOpenCL() != obj &&
|
| | | !buffers[i].BufferRead())
|
| | | ReturnFalseEx(labels[i] + " read");
|
| | | }
|
| | |
|
| | | //--- Recreate only foreign or host-only Bank slots, retaining target-resident values.
|
| | | for(int i = 0; i < 42; i++)
|
| | | if(buffers[i].GetOpenCL() != obj || buffers[i].GetIndex() < 0)
|
| | | if(!buffers[i].BufferCreate(obj))
|
| | | ReturnFalseEx(labels[i] + " create");
|
| | |
|
| | | //--- Transfer Item-owned state and publish the outer context only after Bank success.
|
| | | if(!CD2SkillItem::SetOpenCLChecked(obj))
|
| | | ReturnFalseEx("checked bank item transfer");
|
| | |
|
| | | //--- Finalize after the qualified Item transfer publishes the outer context.
|
| | | return(true);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Scores all slots against the state and gathers the winning |
|
| | | //| correction into the selected buffers. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-21 08:18:10 +03:00 | | | bool CD2SkillBank::Retrieve(CBufferFloat *state, const bool mark_retrieved)
|
2026-08-18 19:58:41 +03:00 | | | {
|
| | | if(!m_enabled || !state || state.Total() != (int)m_dimension ||
|
| | | state.GetOpenCL() != OpenCL || state.GetIndex() < 0 ||
|
| | | !EnsureRetrievalScratch())
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | uint score_local_size = 0;
|
| | | uint partial_count = 0;
|
| | | if(!RetrievalLaunchLayout(score_local_size, partial_count))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | uint offset[1] = {0};
|
| | | const int score_kernel = def_k_D2SkillScoreSlots;
|
| | | setBuffer(score_kernel, def_k_d2ss_query, state.GetIndex())
|
| | | setBuffer(score_kernel, def_k_d2ss_keys, m_keys.GetIndex())
|
2026-08-20 19:55:53 +03:00 | | | setBuffer(score_kernel, def_k_d2ss_partials, m_score_partials.GetIndex())
|
2026-08-18 19:58:41 +03:00 | | | setArgument(score_kernel, def_k_d2ss_slots, (int)m_slots)
|
| | | setArgument(score_kernel, def_k_d2ss_dimension, (int)m_dimension)
|
2026-08-20 19:55:53 +03:00 | | | const uint score_items = m_slots * m_dimension;
|
| | | const uint score_padded = ((score_items + score_local_size - 1) / score_local_size) * score_local_size;
|
| | | uint score_global[1] = {score_padded};
|
2026-08-18 19:58:41 +03:00 | | | uint score_local[1] = {score_local_size};
|
| | | kernelExecuteLoc(score_kernel, offset, score_global, score_local)
|
2026-08-20 19:55:53 +03:00 | | | if(!RunStagedReduction(m_score_partials, m_score_metrics, m_dimension, m_slots, 4,
|
| | | score_local_size))
|
| | | ReturnFalse;
|
| | | const int finalize_kernel = def_k_D2SkillScoreFinalize;
|
| | | setBuffer(finalize_kernel, def_k_d2sf_metrics, m_score_metrics.GetIndex())
|
| | | setBuffer(finalize_kernel, def_k_d2sf_utility, m_utility.GetIndex())
|
| | | setBuffer(finalize_kernel, def_k_d2sf_used, m_used.GetIndex())
|
| | | setBuffer(finalize_kernel, def_k_d2sf_state, m_state.GetIndex())
|
| | | setBuffer(finalize_kernel, def_k_d2sf_scores, m_retrieval_scores.GetIndex())
|
| | | setArgument(finalize_kernel, def_k_d2sf_slots, (int)m_slots)
|
| | | setArgument(finalize_kernel, def_k_d2sf_similarity_threshold, m_similarity_threshold)
|
| | | setArgument(finalize_kernel, def_k_d2sf_utility_weight, m_utility_weight)
|
| | | setArgument(finalize_kernel, def_k_d2sf_min_utility, m_min_utility)
|
| | | setArgument(finalize_kernel, def_k_d2sf_utility_policy, (int)m_utility_aware)
|
2026-08-22 20:08:02 +03:00 | | | const uint finalize_local_size = D2LaunchLocalSize(m_slots);
|
| | | if(finalize_local_size == 0)
|
| | | ReturnFalse;
|
| | | const uint finalize_padded = ((m_slots + finalize_local_size - 1) /
|
| | | finalize_local_size) * finalize_local_size;
|
2026-08-20 19:55:53 +03:00 | | | uint finalize_global[1] = {finalize_padded};
|
2026-08-22 20:08:02 +03:00 | | | uint finalize_local[1] = {finalize_local_size};
|
| | | kernelExecuteLoc(finalize_kernel, offset, finalize_global, finalize_local)
|
2026-08-18 19:58:41 +03:00 | | | //--- Reuse the generic RAG Top-1 contracts without changing their data
|
| | | //--- layout: float scores become float2(slot, score) ping-pong candidates.
|
| | | const uint block_size = RAG_TOPK_LOCAL_WIDTH;
|
| | | const uint top_k = 1;
|
| | | const int partial_kernel = def_k_RAGPartial;
|
| | | setBuffer(partial_kernel, def_k_ragp_scores, m_retrieval_scores.GetIndex())
|
| | | setBuffer(partial_kernel, def_k_ragp_partial, m_retrieval_partial.GetIndex())
|
| | | setArgument(partial_kernel, def_k_ragp_scenario_count, (int)m_slots)
|
| | | setArgument(partial_kernel, def_k_ragp_block_size, (int)block_size)
|
| | | setArgument(partial_kernel, def_k_ragp_top_k, (int)top_k)
|
| | | uint partial_global[1] = {partial_count * block_size};
|
| | | uint partial_local[1] = {block_size};
|
| | | kernelExecuteLoc(partial_kernel, offset, partial_global, partial_local)
|
| | | uint merge_count = partial_count;
|
| | | CBufferFloat *source = GetPointer(m_retrieval_partial);
|
| | | CBufferFloat *destination = GetPointer(m_retrieval_merge);
|
| | | const int merge_kernel = def_k_RAGMerge;
|
| | | while(merge_count > block_size)
|
| | | {
|
| | | const uint merge_blocks = (merge_count + block_size - 1) / block_size;
|
| | | const uint next_count = merge_blocks * top_k;
|
| | | setBuffer(merge_kernel, def_k_ragm_source, source.GetIndex())
|
| | | setBuffer(merge_kernel, def_k_ragm_destination, destination.GetIndex())
|
| | | setArgument(merge_kernel, def_k_ragm_candidate_count, (int)merge_count)
|
| | | setArgument(merge_kernel, def_k_ragm_block_size, (int)block_size)
|
| | | setArgument(merge_kernel, def_k_ragm_top_k, (int)top_k)
|
| | | uint merge_global[1] = {merge_blocks * block_size};
|
| | | uint merge_local[1] = {block_size};
|
| | | kernelExecuteLoc(merge_kernel, offset, merge_global, merge_local)
|
| | | merge_count = next_count;
|
| | | CBufferFloat *swap = source;
|
| | | source = destination;
|
| | | destination = swap;
|
| | | }
|
| | | setBuffer(merge_kernel, def_k_ragm_source, source.GetIndex())
|
| | | setBuffer(merge_kernel, def_k_ragm_destination, m_retrieval_top.GetIndex())
|
| | | setArgument(merge_kernel, def_k_ragm_candidate_count, (int)merge_count)
|
| | | setArgument(merge_kernel, def_k_ragm_block_size, (int)block_size)
|
| | | setArgument(merge_kernel, def_k_ragm_top_k, (int)top_k)
|
| | | uint merge_global[1] = {block_size};
|
| | | uint merge_local[1] = {block_size};
|
| | | kernelExecuteLoc(merge_kernel, offset, merge_global, merge_local)
|
| | | const int gather_kernel = def_k_D2SkillGatherCorrection;
|
| | | setBuffer(gather_kernel, def_k_d2gc_top, m_retrieval_top.GetIndex())
|
| | | setBuffer(gather_kernel, def_k_d2gc_corrections, m_corrections.GetIndex())
|
| | | setBuffer(gather_kernel, def_k_d2gc_directions, m_directions.GetIndex())
|
| | | setBuffer(gather_kernel, def_k_d2gc_scales, m_scales.GetIndex())
|
| | | setBuffer(gather_kernel, def_k_d2gc_selected_correction, m_selected_correction.GetIndex())
|
| | | setBuffer(gather_kernel, def_k_d2gc_selected_slot, m_selected_slot.GetIndex())
|
| | | setBuffer(gather_kernel, def_k_d2gc_selected_score, m_selected_score.GetIndex())
|
| | | setBuffer(gather_kernel, def_k_d2gc_uses, m_uses.GetIndex())
|
| | | setBuffer(gather_kernel, def_k_d2gc_diagnostics, m_diagnostics.GetIndex())
|
| | | setArgument(gather_kernel, def_k_d2gc_slots, (int)m_slots)
|
| | | setArgument(gather_kernel, def_k_d2gc_dimension, (int)m_dimension)
|
| | | setArgument(gather_kernel, def_k_d2gc_representation, (int)m_representation)
|
| | | setArgument(gather_kernel, def_k_d2gc_alpha, m_alpha)
|
2026-08-20 19:55:53 +03:00 | | | setBuffer(gather_kernel, def_k_d2gc_retrieved, m_retrieved.GetIndex())
|
2026-08-21 08:18:10 +03:00 | | | setArgument(gather_kernel, def_k_d2gc_mark_retrieved, (int)mark_retrieved)
|
2026-08-18 19:58:41 +03:00 | | | uint gather_global[1] = {m_dimension};
|
| | | kernelExecute(gather_kernel, offset, gather_global)
|
| | | return(true);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Retrieves the best correction for the source and applies the item|
|
| | | //| residual. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-18 19:58:41 +03:00 | | | bool CD2SkillBank::feedForward(CNeuronBaseOCL *NeuronOCL)
|
| | | {
|
| | | if(!OpenCL || CheckPointer(NeuronOCL) == POINTER_INVALID ||
|
| | | CheckPointer(Output) == POINTER_INVALID)
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | CBufferFloat *source = NeuronOCL.getOutput();
|
| | | if(!source || source.Total() != (int)m_dimension || source.GetOpenCL() != OpenCL)
|
| | | {
|
| | | PrintFormat("D2SkillBank forward contract: source=%p total=%d expected=%u source_cl=%p bank_cl=%p",
|
| | | source, (source ? source.Total() : -1), m_dimension,
|
| | | (source ? source.GetOpenCL() : NULL), OpenCL);
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | }
|
| | | if(!m_enabled)
|
2026-08-20 22:59:48 +03:00 | | | return(CopyBufferRaw(source, Output, m_dimension));
|
2026-08-18 19:58:41 +03:00 | | | if(!Retrieve(source))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | //--- CD2SkillItem owns the residual application. The bank only selects
|
| | | //--- m_selected_correction and exposes it through the inherited buffer.
|
| | | return(CD2SkillItem::feedForward(NeuronOCL));
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-08-21 08:18:10 +03:00 | | | //| Select the current slot without routing its correction. |
|
| | | //+------------------------------------------------------------------+
|
| | | bool CD2SkillBank::Observe(CNeuronBaseOCL *NeuronOCL)
|
| | | {
|
| | | if(!OpenCL || !m_enabled || CheckPointer(NeuronOCL) == POINTER_INVALID)
|
| | | ReturnFalse;
|
| | | CBufferFloat *source = NeuronOCL.getOutput();
|
| | | if(!source || source.Total() != (int)m_dimension || source.GetOpenCL() != OpenCL ||
|
| | | source.GetIndex() < 0)
|
| | | ReturnFalse;
|
| | | return(Retrieve(source, false));
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Accumulates g dot (alpha * correction) for the forward winner. |
|
2026-08-20 22:59:48 +03:00 | | | //+------------------------------------------------------------------+
|
| | | bool CD2SkillBank::AccumulateInfluenceFromGradient(CBufferFloat *gradient)
|
| | | {
|
| | | if(!m_enabled || !OpenCL || !gradient || gradient.Total() != (int)m_dimension ||
|
| | | gradient.GetOpenCL() != OpenCL || gradient.GetIndex() < 0 ||
|
| | | m_selected_correction.GetIndex() < 0 || m_selected_slot.GetIndex() < 0 ||
|
| | | m_influence.GetIndex() < 0 || !EnsureUpdateScratch())
|
| | | ReturnFalse;
|
| | | uint local_size = 0;
|
| | | uint groups = 0;
|
| | | if(!UpdateLaunchLayout(local_size, groups))
|
| | | ReturnFalse;
|
| | | uint offset[1] = {0};
|
| | | uint local[1] = {local_size};
|
| | | const int partial_kernel = def_k_D2SkillInfluencePartial;
|
| | | setBuffer(partial_kernel, def_k_d2sip_gradient, gradient.GetIndex())
|
| | | setBuffer(partial_kernel, def_k_d2sip_correction, m_selected_correction.GetIndex())
|
| | | setBuffer(partial_kernel, def_k_d2sip_partials, m_gradient_influence_partials.GetIndex())
|
| | | setArgument(partial_kernel, def_k_d2sip_dimension, (int)m_dimension)
|
| | | uint global[1] = {groups * local_size};
|
| | | kernelExecuteLoc(partial_kernel, offset, global, local)
|
| | | if(!RunStagedReduction(m_gradient_influence_partials, m_gradient_influence_total,
|
| | | m_dimension, 1, 1, local_size))
|
| | | ReturnFalse;
|
| | | const int accumulate_kernel = def_k_D2SkillInfluenceAccumulate;
|
| | | setBuffer(accumulate_kernel, def_k_d2sia_selected_slot, m_selected_slot.GetIndex())
|
| | | setBuffer(accumulate_kernel, def_k_d2sia_reduced_influence,
|
| | | m_gradient_influence_total.GetIndex())
|
| | | setBuffer(accumulate_kernel, def_k_d2sia_influence, m_influence.GetIndex())
|
| | | setArgument(accumulate_kernel, def_k_d2sia_slots, (int)m_slots)
|
| | | uint scalar_global[1] = {1};
|
| | | kernelExecute(accumulate_kernel, offset, scalar_global)
|
| | | return(true);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Updates only the direction EMA of the retrieved stable slot. |
|
2026-08-21 08:18:10 +03:00 | | | //+------------------------------------------------------------------+
|
| | | bool CD2SkillBank::UpdateDirectionFromGradient(CBufferFloat *gradient)
|
| | | {
|
| | | if(!m_enabled || !OpenCL || !gradient || gradient.Total() != (int)m_dimension ||
|
| | | gradient.GetOpenCL() != OpenCL || gradient.GetIndex() < 0 ||
|
| | | m_selected_slot.GetIndex() < 0 || !EnsureItemState())
|
| | | ReturnFalse;
|
| | | uint local_size = 0;
|
| | | uint groups = 0;
|
| | | uint partial_count = 0;
|
2026-08-22 20:08:02 +03:00 | | | if(!ItemLaunchLayout(local_size, groups, partial_count))
|
| | | ReturnFalse;
|
| | | const int normalize_kernel = def_k_D2SkillNormalizeDirection;
|
| | | setBuffer(normalize_kernel, def_k_d2nd_directions, m_directions.GetIndex())
|
| | | setBuffer(normalize_kernel, def_k_d2nd_selected_slot, m_selected_slot.GetIndex())
|
| | | setBuffer(normalize_kernel, def_k_d2nd_used, m_used.GetIndex())
|
| | | setBuffer(normalize_kernel, def_k_d2nd_state, m_state.GetIndex())
|
| | | setBuffer(normalize_kernel, def_k_d2nd_partials, m_item_partials.GetIndex())
|
| | | setBuffer(normalize_kernel, def_k_d2nd_reduced_norm, m_item_reduced_norm.GetIndex())
|
| | | setArgument(normalize_kernel, def_k_d2nd_slots, (int)m_slots)
|
| | | setArgument(normalize_kernel, def_k_d2nd_dimension, (int)m_dimension)
|
| | | setArgument(normalize_kernel, def_k_d2nd_phase, 0)
|
| | | uint offset[1] = {0};
|
| | | uint global[1] = {groups * local_size};
|
| | | uint local[1] = {local_size};
|
| | | kernelExecuteLoc(normalize_kernel, offset, global, local)
|
| | | if(!RunStagedReduction(m_item_partials, m_item_reduced_norm, m_dimension, 1, 1,
|
| | | local_size))
|
| | | ReturnFalse;
|
| | | setArgument(normalize_kernel, def_k_d2nd_phase, 1)
|
| | | kernelExecuteLoc(normalize_kernel, offset, global, local)
|
| | | if(!CalculateItemNorm(gradient, local_size, groups))
|
2026-08-21 08:18:10 +03:00 | | | ReturnFalse;
|
| | | const int kernel = def_k_D2SkillDirectionEMA;
|
| | | setBuffer(kernel, def_k_d2de_gradient, gradient.GetIndex())
|
| | | setBuffer(kernel, def_k_d2de_directions, m_directions.GetIndex())
|
| | | setBuffer(kernel, def_k_d2de_selected_slot, m_selected_slot.GetIndex())
|
| | | setBuffer(kernel, def_k_d2de_used, m_used.GetIndex())
|
| | | setBuffer(kernel, def_k_d2de_state, m_state.GetIndex())
|
| | | setBuffer(kernel, def_k_d2de_reduced_norm, m_item_reduced_norm.GetIndex())
|
2026-08-22 20:08:02 +03:00 | | | setBuffer(kernel, def_k_d2de_partials, m_item_partials.GetIndex())
|
2026-08-21 08:18:10 +03:00 | | | setArgument(kernel, def_k_d2de_slots, (int)m_slots)
|
| | | setArgument(kernel, def_k_d2de_dimension, (int)m_dimension)
|
| | | setArgument(kernel, def_k_d2de_beta_direction, m_beta_direction)
|
2026-08-22 20:08:02 +03:00 | | | setArgument(kernel, def_k_d2de_phase, 0)
|
| | | kernelExecuteLoc(kernel, offset, global, local)
|
| | | if(!RunStagedReduction(m_item_partials, m_item_reduced_norm, m_dimension, 1, 1,
|
| | | local_size))
|
| | | ReturnFalse;
|
| | | setArgument(kernel, def_k_d2de_phase, 1)
|
2026-08-21 08:18:10 +03:00 | | | kernelExecuteLoc(kernel, offset, global, local)
|
| | | return(true);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Runs the full bank update: lifecycle ages, metrics, candidate |
|
| | | //| promotion and EMA vector update. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-18 19:58:41 +03:00 | | | bool CD2SkillBank::UpdateFromGradient(CBufferFloat *state, CBufferFloat *gradient)
|
| | | {
|
| | | //--- The D2 update consumes the pseudo-residual g=-dL_Actor/dh.
|
| | | //--- CNeuronBaseOCL::calcOutputGradients writes target-output (the
|
| | | //--- negative MSE derivative), so the gradient buffer is already g and
|
| | | //--- must not be negated again here. Direct callers must provide the
|
| | | //--- same pseudo-residual contract.
|
| | | if(!m_enabled || !OpenCL || !state || !gradient ||
|
2026-08-20 19:55:53 +03:00 | | | state.Total() != (int)m_dimension || gradient.Total() != (int)m_dimension ||
|
| | | state.GetOpenCL() != OpenCL || gradient.GetOpenCL() != OpenCL ||
|
| | | !EnsureUpdateScratch())
|
| | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | uint local_size = 0;
|
| | | uint groups = 0;
|
| | | if(!UpdateLaunchLayout(local_size, groups))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | uint offset[1] = {0};
|
| | | const int age_kernel = def_k_D2SkillAgeLifecycle;
|
| | | setBuffer(age_kernel, def_k_d2al_used, m_used.GetIndex())
|
| | | setBuffer(age_kernel, def_k_d2al_state, m_state.GetIndex())
|
| | | setBuffer(age_kernel, def_k_d2al_age, m_age.GetIndex())
|
| | | setBuffer(age_kernel, def_k_d2al_protection, m_protection.GetIndex())
|
| | | setBuffer(age_kernel, def_k_d2al_utility, m_utility.GetIndex())
|
| | | setBuffer(age_kernel, def_k_d2al_free_scores, m_free_scores.GetIndex())
|
| | | setBuffer(age_kernel, def_k_d2al_eviction_scores, m_eviction_scores.GetIndex())
|
| | | setArgument(age_kernel, def_k_d2al_slots, (int)m_slots)
|
| | | setArgument(age_kernel, def_k_d2al_inactivity_age, (int)m_inactivity_age)
|
2026-08-20 19:55:53 +03:00 | | | setBuffer(age_kernel, def_k_d2al_retrieved, m_retrieved.GetIndex())
|
| | | setBuffer(age_kernel, def_k_d2al_candidate_scores, m_retrieval_scores.GetIndex())
|
2026-08-18 19:58:41 +03:00 | | | uint slot_global[1] = {m_slots};
|
| | | kernelExecute(age_kernel, offset, slot_global)
|
| | | if(!RunTop1(m_free_scores, m_free_top) || !RunTop1(m_eviction_scores, m_eviction_top) ||
|
2026-08-20 19:55:53 +03:00 | | | !RunTop1(m_retrieval_scores, m_retrieval_top) ||
|
2026-08-18 19:58:41 +03:00 | | | !RunMetrics(state, gradient, local_size, groups))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | const int leader_kernel = def_k_D2SkillCandidateLeader;
|
| | | setBuffer(leader_kernel, def_k_d2cl_selected_slot, m_selected_slot.GetIndex())
|
| | | setBuffer(leader_kernel, def_k_d2cl_used, m_used.GetIndex())
|
| | | setBuffer(leader_kernel, def_k_d2cl_scales, m_scales.GetIndex())
|
| | | setBuffer(leader_kernel, def_k_d2cl_observations, m_observations.GetIndex())
|
| | | setBuffer(leader_kernel, def_k_d2cl_mass, m_mass.GetIndex())
|
| | | setBuffer(leader_kernel, def_k_d2cl_age, m_age.GetIndex())
|
2026-08-20 19:55:53 +03:00 | | | setBuffer(leader_kernel, def_k_d2cl_candidate_streak, m_observations.GetIndex())
|
| | | setBuffer(leader_kernel, def_k_d2cl_candidate_valid, m_state.GetIndex())
|
| | | setBuffer(leader_kernel, def_k_d2cl_candidate_scale, m_scales.GetIndex())
|
2026-08-18 19:58:41 +03:00 | | | setBuffer(leader_kernel, def_k_d2cl_metrics, m_metrics.GetIndex())
|
| | | setBuffer(leader_kernel, def_k_d2cl_free_top, m_free_top.GetIndex())
|
| | | setBuffer(leader_kernel, def_k_d2cl_eviction_top, m_eviction_top.GetIndex())
|
| | | setBuffer(leader_kernel, def_k_d2cl_decision, m_decision.GetIndex())
|
| | | setBuffer(leader_kernel, def_k_d2cl_diagnostics, m_diagnostics.GetIndex())
|
| | | setArgument(leader_kernel, def_k_d2cl_slots, (int)m_slots)
|
| | | setArgument(leader_kernel, def_k_d2cl_representation, (int)m_representation)
|
| | | setArgument(leader_kernel, def_k_d2cl_beta_magnitude, m_beta_magnitude)
|
| | | setArgument(leader_kernel, def_k_d2cl_max_correction, m_max_correction)
|
| | | setArgument(leader_kernel, def_k_d2cl_min_confirmations, (int)m_min_confirmations)
|
| | | setArgument(leader_kernel, def_k_d2cl_similarity_threshold, m_similarity_threshold)
|
| | | setArgument(leader_kernel, def_k_d2cl_direction_threshold, m_direction_threshold)
|
2026-08-20 19:55:53 +03:00 | | | setBuffer(leader_kernel, def_k_d2cl_candidate_top, m_retrieval_top.GetIndex())
|
| | | setBuffer(leader_kernel, def_k_d2cl_candidate_protection, m_protection.GetIndex())
|
2026-08-18 19:58:41 +03:00 | | | uint scalar_global[1] = {1};
|
| | | kernelExecute(leader_kernel, offset, scalar_global)
|
| | | const int vector_kernel = def_k_D2SkillVectorUpdate;
|
| | | setBuffer(vector_kernel, def_k_d2vu_query, state.GetIndex())
|
| | | setBuffer(vector_kernel, def_k_d2vu_gradient, gradient.GetIndex())
|
| | | setBuffer(vector_kernel, def_k_d2vu_keys, m_keys.GetIndex())
|
| | | setBuffer(vector_kernel, def_k_d2vu_corrections, m_corrections.GetIndex())
|
| | | setBuffer(vector_kernel, def_k_d2vu_directions, m_directions.GetIndex())
|
| | | setBuffer(vector_kernel, def_k_d2vu_scales, m_scales.GetIndex())
|
2026-08-20 19:55:53 +03:00 | | | setBuffer(vector_kernel, def_k_d2vu_candidate_key, m_keys.GetIndex())
|
| | | setBuffer(vector_kernel, def_k_d2vu_candidate_direction, m_directions.GetIndex())
|
| | | setBuffer(vector_kernel, def_k_d2vu_candidate_scale, m_scales.GetIndex())
|
2026-08-18 19:58:41 +03:00 | | | setBuffer(vector_kernel, def_k_d2vu_decision, m_decision.GetIndex())
|
| | | setBuffer(vector_kernel, def_k_d2vu_reduced_norm, m_item_reduced_norm.GetIndex())
|
| | | setArgument(vector_kernel, def_k_d2vu_dimension, (int)m_dimension)
|
| | | setArgument(vector_kernel, def_k_d2vu_representation, (int)m_representation)
|
| | | setArgument(vector_kernel, def_k_d2vu_beta_correction, m_beta_correction)
|
| | | setArgument(vector_kernel, def_k_d2vu_beta_direction, m_beta_direction)
|
| | | setArgument(vector_kernel, def_k_d2vu_beta_key, m_beta_key)
|
| | | setArgument(vector_kernel, def_k_d2vu_max_correction, m_max_correction)
|
| | | setArgument(vector_kernel, def_k_d2vu_phase, 0)
|
| | | uint vector_global[1] = {groups * local_size};
|
| | | uint vector_local[1] = {local_size};
|
| | | kernelExecuteLoc(vector_kernel, offset, vector_global, vector_local)
|
| | | if(!CalculateBankVectorNorm(local_size, groups))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | setArgument(vector_kernel, def_k_d2vu_phase, 1)
|
| | | kernelExecuteLoc(vector_kernel, offset, vector_global, vector_local)
|
| | | const int promote_kernel = def_k_D2SkillPromoteSlot;
|
| | | setBuffer(promote_kernel, def_k_d2ps_scales, m_scales.GetIndex())
|
| | | setBuffer(promote_kernel, def_k_d2ps_utility, m_utility.GetIndex())
|
| | | setBuffer(promote_kernel, def_k_d2ps_observations, m_observations.GetIndex())
|
| | | setBuffer(promote_kernel, def_k_d2ps_uses, m_uses.GetIndex())
|
| | | setBuffer(promote_kernel, def_k_d2ps_mass, m_mass.GetIndex())
|
| | | setBuffer(promote_kernel, def_k_d2ps_used, m_used.GetIndex())
|
| | | setBuffer(promote_kernel, def_k_d2ps_state, m_state.GetIndex())
|
| | | setBuffer(promote_kernel, def_k_d2ps_age, m_age.GetIndex())
|
| | | setBuffer(promote_kernel, def_k_d2ps_protection, m_protection.GetIndex())
|
2026-08-20 19:55:53 +03:00 | | | setBuffer(promote_kernel, def_k_d2ps_candidate_streak, m_observations.GetIndex())
|
| | | setBuffer(promote_kernel, def_k_d2ps_candidate_valid, m_state.GetIndex())
|
| | | setBuffer(promote_kernel, def_k_d2ps_candidate_scale, m_scales.GetIndex())
|
2026-08-18 19:58:41 +03:00 | | | setBuffer(promote_kernel, def_k_d2ps_decision, m_decision.GetIndex())
|
| | | setBuffer(promote_kernel, def_k_d2ps_diagnostics, m_diagnostics.GetIndex())
|
| | | setArgument(promote_kernel, def_k_d2ps_slots, (int)m_slots)
|
| | | setArgument(promote_kernel, def_k_d2ps_protection_age, (int)m_protection_age)
|
| | | kernelExecute(promote_kernel, offset, scalar_global)
|
| | | return(true);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Applies the utility EMA from episode influence and reports |
|
| | | //| whether it was applied. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-27 11:39:46 +03:00 | | | bool CD2SkillBank::UpdateUtility(const float delta_j, bool &applied)
|
2026-08-18 19:58:41 +03:00 | | | {
|
2026-08-27 11:39:46 +03:00 | | | applied = false;
|
2026-08-20 19:55:53 +03:00 | | | if(!m_enabled || !OpenCL || !MathIsValidNumber(delta_j) || !EnsureUpdateScratch())
|
| | | ReturnFalse;
|
| | | uint local_size = 0;
|
| | | uint groups = 0;
|
| | | if(!UpdateLaunchLayout(local_size, groups))
|
| | | ReturnFalse;
|
| | | const int total_kernel = def_k_D2SkillInfluenceTotal;
|
| | | setBuffer(total_kernel, def_k_d2it_influence, m_influence.GetIndex())
|
| | | setBuffer(total_kernel, def_k_d2it_used, m_used.GetIndex())
|
| | | setBuffer(total_kernel, def_k_d2it_state, m_state.GetIndex())
|
| | | setBuffer(total_kernel, def_k_d2it_partials, m_influence_partials.GetIndex())
|
| | | setArgument(total_kernel, def_k_d2it_slots, (int)m_slots)
|
| | | uint offset[1] = {0};
|
| | | const uint slot_padded = ((m_slots + local_size - 1) / local_size) * local_size;
|
| | | uint slot_global[1] = {slot_padded};
|
| | | uint local[1] = {local_size};
|
| | | kernelExecuteLoc(total_kernel, offset, slot_global, local)
|
| | | if(!RunStagedReduction(m_influence_partials, m_influence_total, m_slots, 1, 1,
|
| | | local_size))
|
| | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | const int kernel = def_k_D2SkillUtility;
|
2026-08-20 19:55:53 +03:00 | | | setBuffer(kernel, def_k_d2ut_influence, m_influence.GetIndex())
|
| | | setBuffer(kernel, def_k_d2ut_influence_total, m_influence_total.GetIndex())
|
2026-08-18 19:58:41 +03:00 | | | setBuffer(kernel, def_k_d2ut_utility, m_utility.GetIndex())
|
| | | setBuffer(kernel, def_k_d2ut_used, m_used.GetIndex())
|
2026-08-20 19:55:53 +03:00 | | | setBuffer(kernel, def_k_d2ut_state, m_state.GetIndex())
|
2026-08-18 19:58:41 +03:00 | | | setBuffer(kernel, def_k_d2ut_diagnostics, m_diagnostics.GetIndex())
|
2026-08-27 11:39:46 +03:00 | | | setBuffer(kernel, def_k_d2ut_applied, m_utility_applied.GetIndex())
|
2026-08-18 19:58:41 +03:00 | | | setArgument(kernel, def_k_d2ut_delta, delta_j)
|
| | | setArgument(kernel, def_k_d2ut_beta, m_beta_utility)
|
| | | setArgument(kernel, def_k_d2ut_slots, (int)m_slots)
|
2026-08-20 19:55:53 +03:00 | | | kernelExecuteLoc(kernel, offset, slot_global, local)
|
2026-08-27 11:39:46 +03:00 | | | if(!RunStagedReduction(m_utility_applied, m_influence_partials,
|
| | | m_influence_total, m_slots, 1, 1,
|
| | | local_size) || !m_influence_total.BufferRead())
|
| | | ReturnFalse;
|
| | | applied = (m_influence_total[0] > 0.5f);
|
2026-08-20 19:55:53 +03:00 | | | return(true);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Applies the utility EMA from episode influence. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-27 11:39:46 +03:00 | | | bool CD2SkillBank::UpdateUtility(const float delta_j)
|
| | | {
|
| | | bool applied = false;
|
| | | return(UpdateUtility(delta_j, applied));
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Zeroes the per-slot influence counters for the current episode. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 19:55:53 +03:00 | | | bool CD2SkillBank::ResetEpisodeInfluence(void)
|
| | | {
|
2026-08-26 18:00:29 +03:00 | | | //--- BASE/disabled banks have no influence buffer by design. Episode cleanup
|
| | | //--- is therefore a successful no-op and must not materialize one.
|
| | | if(!m_enabled)
|
| | | return(true);
|
2026-08-20 19:55:53 +03:00 | | | if(!OpenCL || m_slots == 0 || m_influence.GetIndex() < 0)
|
| | | ReturnFalse;
|
| | | const int kernel = def_k_D2SkillResetInfluence;
|
| | | setBuffer(kernel, def_k_d2ri_influence, m_influence.GetIndex())
|
| | | setArgument(kernel, def_k_d2ri_slots, (int)m_slots)
|
2026-08-18 19:58:41 +03:00 | | | uint offset[1] = {0};
|
2026-08-20 19:55:53 +03:00 | | | uint global[1] = {m_slots};
|
2026-08-18 19:58:41 +03:00 | | | kernelExecute(kernel, offset, global)
|
| | | return(true);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Recomputes bank diagnostics, norms and the utility/usage |
|
| | | //| distributions. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-18 19:58:41 +03:00 | | | bool CD2SkillBank::RefreshDiagnostics(void)
|
| | | {
|
2026-08-26 18:00:29 +03:00 | | | //--- OOS reporting may inspect every branch. Disabled branches report their
|
| | | //--- caller-provided zero counters without allocating diagnostics scratch.
|
| | | if(!m_enabled)
|
| | | return(true);
|
2026-08-18 19:58:41 +03:00 | | | if(!OpenCL || !ValidateBuffers() || !EnsureUpdateScratch())
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | uint local_size = 0;
|
| | | uint groups = 0;
|
| | | if(!UpdateLaunchLayout(local_size, groups))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | uint offset[1] = {0};
|
2026-08-20 19:55:53 +03:00 | | | uint local[1] = {local_size};
|
| | | const uint vector_items = m_slots * m_dimension;
|
| | | const uint vector_padded = ((vector_items + local_size - 1) / local_size) * local_size;
|
| | | const int norm_kernel = def_k_D2SkillDiagnosticsNormPartial;
|
| | | setBuffer(norm_kernel, def_k_d2dnp_corrections, m_corrections.GetIndex())
|
| | | setBuffer(norm_kernel, def_k_d2dnp_partials, m_diagnostics_norm_partials.GetIndex())
|
| | | setArgument(norm_kernel, def_k_d2dnp_slots, (int)m_slots)
|
| | | setArgument(norm_kernel, def_k_d2dnp_dimension, (int)m_dimension)
|
| | | uint norm_global[1] = {vector_padded};
|
| | | kernelExecuteLoc(norm_kernel, offset, norm_global, local)
|
| | | if(!RunStagedReduction(m_diagnostics_norm_partials, m_diagnostics_norms,
|
| | | m_dimension, m_slots, 1, local_size))
|
| | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | const int partial_kernel = def_k_D2SkillDiagnosticsPartial;
|
2026-08-20 19:55:53 +03:00 | | | setBuffer(partial_kernel, def_k_d2dp_norms, m_diagnostics_norms.GetIndex())
|
2026-08-18 19:58:41 +03:00 | | | setBuffer(partial_kernel, def_k_d2dp_utility, m_utility.GetIndex())
|
| | | setBuffer(partial_kernel, def_k_d2dp_uses, m_uses.GetIndex())
|
| | | setBuffer(partial_kernel, def_k_d2dp_used, m_used.GetIndex())
|
| | | setBuffer(partial_kernel, def_k_d2dp_state, m_state.GetIndex())
|
| | | setBuffer(partial_kernel, def_k_d2dp_age, m_age.GetIndex())
|
| | | setBuffer(partial_kernel, def_k_d2dp_partials, m_diagnostics_partials.GetIndex())
|
| | | setArgument(partial_kernel, def_k_d2dp_slots, (int)m_slots)
|
2026-08-20 19:55:53 +03:00 | | | const uint slot_padded = ((m_slots + local_size - 1) / local_size) * local_size;
|
| | | uint partial_global[1] = {slot_padded};
|
| | | kernelExecuteLoc(partial_kernel, offset, partial_global, local)
|
| | | if(!RunStagedReduction(m_diagnostics_partials, m_diagnostics_totals, m_slots, 1,
|
| | | D2SKILL_DIAGNOSTIC_PARTIALS, local_size, 9, 10))
|
| | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | const int reduce_kernel = def_k_D2SkillDiagnosticsReduce;
|
2026-08-20 19:55:53 +03:00 | | | setBuffer(reduce_kernel, def_k_d2dr_totals, m_diagnostics_totals.GetIndex())
|
2026-08-18 19:58:41 +03:00 | | | setBuffer(reduce_kernel, def_k_d2dr_diagnostics, m_diagnostics.GetIndex())
|
| | | setBuffer(reduce_kernel, def_k_d2dr_utility_distribution, m_utility_distribution.GetIndex())
|
| | | setBuffer(reduce_kernel, def_k_d2dr_usage_distribution, m_usage_distribution.GetIndex())
|
| | | setArgument(reduce_kernel, def_k_d2dr_slots, (int)m_slots)
|
2026-08-20 19:55:53 +03:00 | | | const uint finalize_padded = ((23 + local_size - 1) / local_size) * local_size;
|
| | | uint reduce_global[1] = {finalize_padded};
|
| | | kernelExecuteLoc(reduce_kernel, offset, reduce_global, local)
|
2026-08-18 19:58:41 +03:00 | | | return(true);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Saves the bank state and diagnostics to the file handle. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-18 19:58:41 +03:00 | | | bool CD2SkillBank::Save(const int file_handle)
|
| | | {
|
| | | if(file_handle == INVALID_HANDLE || !RefreshDiagnostics() || !CNeuronBaseOCL::Save(file_handle))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | dFileWriteUInt(file_handle, D2SKILL_FORMAT);
|
| | | dFileWriteUInt(file_handle, m_slots);
|
| | | dFileWriteUInt(file_handle, m_dimension);
|
| | | dFileWriteUInt(file_handle, (uint)m_representation);
|
| | | dFileWriteUInt(file_handle, (uint)m_enabled);
|
| | | dFileWriteUInt(file_handle, m_min_confirmations);
|
| | | dFileWriteUInt(file_handle, m_protection_age);
|
| | | dFileWriteUInt(file_handle, m_inactivity_age);
|
| | | dFileWriteFloat(file_handle, m_similarity_threshold);
|
| | | dFileWriteFloat(file_handle, m_direction_threshold);
|
| | | dFileWriteFloat(file_handle, m_utility_weight);
|
| | | dFileWriteFloat(file_handle, m_alpha);
|
| | | dFileWriteFloat(file_handle, m_min_utility);
|
| | | dFileWriteUInt(file_handle, (uint)m_utility_aware);
|
| | | dFileWriteFloat(file_handle, m_beta_key);
|
| | | dFileWriteFloat(file_handle, m_beta_utility);
|
| | | dFileWriteFloat(file_handle, m_max_correction);
|
| | | dFileWriteFloat(file_handle, m_beta_correction);
|
| | | dFileWriteFloat(file_handle, m_beta_direction);
|
| | | dFileWriteFloat(file_handle, m_beta_magnitude);
|
| | | return(m_keys.Save(file_handle) && m_corrections.Save(file_handle) &&
|
| | | m_directions.Save(file_handle) && m_scales.Save(file_handle) &&
|
| | | m_utility.Save(file_handle) && m_observations.Save(file_handle) &&
|
| | | m_uses.Save(file_handle) && m_mass.Save(file_handle) && m_used.Save(file_handle) &&
|
| | | m_state.Save(file_handle) && m_age.Save(file_handle) && m_protection.Save(file_handle) &&
|
2026-08-20 19:55:53 +03:00 | | | m_influence.Save(file_handle) && m_selected_correction.Save(file_handle) &&
|
2026-08-18 19:58:41 +03:00 | | | m_selected_slot.Save(file_handle) && m_selected_score.Save(file_handle) &&
|
| | | m_diagnostics.Save(file_handle) &&
|
| | | m_utility_distribution.Save(file_handle) &&
|
| | | m_usage_distribution.Save(file_handle));
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Restores the bank state from the file handle, deferring device |
|
| | | //| attachment. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-18 19:58:41 +03:00 | | | bool CD2SkillBank::Load(const int file_handle)
|
| | | {
|
| | | if(file_handle == INVALID_HANDLE || !CNeuronBaseOCL::Load(file_handle))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | const uint format = (uint)FileReadInteger(file_handle);
|
2026-08-20 19:55:53 +03:00 | | | if(format != D2SKILL_FORMAT)
|
| | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | m_slots = (uint)FileReadInteger(file_handle);
|
| | | m_dimension = (uint)FileReadInteger(file_handle);
|
| | | m_item_dimension = m_dimension;
|
| | | m_representation = (ED2SkillRepresentation)FileReadInteger(file_handle);
|
| | | m_enabled = (FileReadInteger(file_handle) != 0);
|
| | | m_min_confirmations = (uint)FileReadInteger(file_handle);
|
| | | m_protection_age = (uint)FileReadInteger(file_handle);
|
| | | m_inactivity_age = (format >= 4 ? (uint)FileReadInteger(file_handle) : 256);
|
| | | dFileReadUFloat(file_handle, m_similarity_threshold);
|
| | | dFileReadUFloat(file_handle, m_direction_threshold);
|
| | | dFileReadUFloat(file_handle, m_utility_weight);
|
| | | if(format >= 5)
|
| | | {
|
| | | dFileReadUFloat(file_handle, m_alpha);
|
| | | dFileReadUFloat(file_handle, m_min_utility);
|
| | | m_utility_aware = (FileReadInteger(file_handle) != 0);
|
| | | }
|
| | | else
|
| | | {
|
| | | m_alpha = 1.0f;
|
| | | m_min_utility = -1.0f;
|
| | | m_utility_aware = false;
|
| | | }
|
| | | dFileReadUFloat(file_handle, m_beta_key);
|
| | | dFileReadUFloat(file_handle, m_beta_utility);
|
| | | dFileReadUFloat(file_handle, m_max_correction);
|
| | | dFileReadUFloat(file_handle, m_beta_correction);
|
| | | dFileReadUFloat(file_handle, m_beta_direction);
|
| | | dFileReadUFloat(file_handle, m_beta_magnitude);
|
| | | if(m_slots == 0 || m_dimension == 0 || m_min_confirmations == 0)
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | const long total = (long)m_slots * (long)m_dimension;
|
| | | if(!m_keys.Load(file_handle) || !m_corrections.Load(file_handle) ||
|
| | | !m_directions.Load(file_handle) || !m_scales.Load(file_handle) ||
|
| | | !m_utility.Load(file_handle) || !m_observations.Load(file_handle) ||
|
| | | !m_uses.Load(file_handle) || !m_mass.Load(file_handle) || !m_used.Load(file_handle) ||
|
| | | !m_state.Load(file_handle) || !m_age.Load(file_handle) || !m_protection.Load(file_handle) ||
|
2026-08-20 19:55:53 +03:00 | | | !m_influence.Load(file_handle) || !m_selected_correction.Load(file_handle) ||
|
2026-08-18 19:58:41 +03:00 | | | !m_selected_slot.Load(file_handle) || !m_selected_score.Load(file_handle))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
| | | if(!m_diagnostics.Load(file_handle))
|
| | | ReturnFalse;
|
| | | if(m_diagnostics.Total() != D2SKILL_DIAGNOSTICS)
|
2026-08-18 19:58:41 +03:00 | | | if(!InitBuffer(m_diagnostics, D2SKILL_DIAGNOSTICS))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
| | | if(!m_utility_distribution.Load(file_handle) ||
|
2026-08-27 11:39:46 +03:00 | | | !m_usage_distribution.Load(file_handle) || !m_utility_applied.BufferInit((int)m_slots, 0.0f) ||
|
| | | !m_influence_total.BufferInit(1, 0.0f) ||
|
2026-08-26 18:00:29 +03:00 | | | !m_gradient_influence_total.BufferInit(1, 0.0f) ||
|
| | | !m_retrieved.BufferInit((int)m_slots, 0.0f))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | if(total > 2147483647 || !ValidateBuffers())
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-26 18:00:29 +03:00 | | | //--- Device attachment is intentionally deferred to CD2Skill::Enable().
|
| | | //--- This keeps disabled Task/Step banks out of a baseline checkpoint load.
|
| | | m_correction = NULL;
|
2026-08-18 19:58:41 +03:00 | | | return(true);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Restores the bank state and attaches the given OpenCL context. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-18 19:58:41 +03:00 | | | bool CD2SkillBank::Load(const int file_handle, COpenCLMy *opencl)
|
| | | {
|
| | | if(file_handle == INVALID_HANDLE || !opencl ||
|
| | | FileReadInteger(file_handle, INT_VALUE) != defNeuronD2SkillBank)
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | OpenCL = opencl;
|
| | | if(!Load(file_handle))
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | SetOpenCL(opencl);
|
| | | return(true);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Clears all bank buffers and resets the active slot. |
|
| | | //+------------------------------------------------------------------+
|
2026-08-18 19:58:41 +03:00 | | | bool CD2SkillBank::Clear(void)
|
| | | {
|
| | | m_correction = NULL;
|
| | | if(!CNeuronBaseOCL::Clear())
|
2026-08-20 19:55:53 +03:00 | | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | m_active_slot = UINT_MAX;
|
2026-08-27 11:39:46 +03:00 | | | if(!(m_retrieved.Fill(0) && m_influence.Fill(0) && m_utility_applied.Fill(0) &&
|
2026-08-21 08:18:10 +03:00 | | | m_influence_total.Fill(0) && m_gradient_influence_total.Fill(0) &&
|
| | | m_selected_correction.Fill(0) && m_selected_slot.Fill(-1.0f) &&
|
| | | m_selected_score.Fill(-3.402823e+38f) && m_diagnostics.Fill(0) &&
|
| | | m_utility_distribution.Fill(0) && m_usage_distribution.Fill(0) &&
|
| | | (m_retrieval_scores.Total() == 0 || m_retrieval_scores.Fill(0)) &&
|
| | | (m_score_partials.Total() == 0 || m_score_partials.Fill(0)) &&
|
| | | (m_score_metrics.Total() == 0 || m_score_metrics.Fill(0)) &&
|
| | | (m_retrieval_partial.Total() == 0 || m_retrieval_partial.Fill(0)) &&
|
| | | (m_retrieval_merge.Total() == 0 || m_retrieval_merge.Fill(0)) &&
|
| | | (m_retrieval_top.Total() == 0 || m_retrieval_top.Fill(0)) &&
|
| | | (m_free_scores.Total() == 0 || m_free_scores.Fill(0)) &&
|
| | | (m_eviction_scores.Total() == 0 || m_eviction_scores.Fill(0)) &&
|
| | | (m_free_top.Total() == 0 || m_free_top.Fill(0)) &&
|
| | | (m_eviction_top.Total() == 0 || m_eviction_top.Fill(0)) &&
|
| | | (m_influence_partials.Total() == 0 || m_influence_partials.Fill(0)) &&
|
| | | (m_gradient_influence_partials.Total() == 0 || m_gradient_influence_partials.Fill(0)) &&
|
| | | (m_metric_partials.Total() == 0 || m_metric_partials.Fill(0)) &&
|
| | | (m_metrics.Total() == 0 || m_metrics.Fill(0)) &&
|
| | | (m_decision.Total() == 0 || m_decision.Fill(0)) &&
|
| | | (m_diagnostics_norm_partials.Total() == 0 || m_diagnostics_norm_partials.Fill(0)) &&
|
| | | (m_diagnostics_norms.Total() == 0 || m_diagnostics_norms.Fill(0)) &&
|
| | | (m_diagnostics_partials.Total() == 0 || m_diagnostics_partials.Fill(0)) &&
|
| | | (m_diagnostics_totals.Total() == 0 || m_diagnostics_totals.Fill(0))))
|
| | | ReturnFalse;
|
| | | return(SetCorrectionBuffer(GetPointer(m_selected_correction)));
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-04 17:39:51 +03:00 | | | //| Explicit destructive reset used only by isolated fixture tests. |
|
2026-08-21 08:18:10 +03:00 | | | //+------------------------------------------------------------------+
|
| | | bool CD2SkillBank::ResetDurableState(void)
|
| | | {
|
| | | if(!Clear())
|
| | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | if(!(m_keys.Fill(0) && m_corrections.Fill(0) && m_directions.Fill(0) &&
|
| | | m_scales.Fill(0) && m_utility.Fill(0) && m_observations.Fill(0) &&
|
| | | m_uses.Fill(0) && m_mass.Fill(0) && m_used.Fill(0) && m_state.Fill(0) &&
|
2026-08-20 19:55:53 +03:00 | | | m_age.Fill(0) && m_protection.Fill(0) && m_influence.Fill(0) &&
|
2026-08-27 11:39:46 +03:00 | | | m_utility_applied.Fill(0) &&
|
2026-08-20 22:59:48 +03:00 | | | m_influence_total.Fill(0) && m_gradient_influence_total.Fill(0) &&
|
| | | m_retrieved.Fill(0) &&
|
2026-08-20 19:55:53 +03:00 | | | m_selected_correction.Fill(0) && m_selected_slot.Fill(-1.0f) &&
|
| | | m_selected_score.Fill(-3.402823e+38f) && m_diagnostics.Fill(0) &&
|
| | | m_utility_distribution.Fill(0) && m_usage_distribution.Fill(0) &&
|
| | | (m_retrieval_scores.Total() == 0 || m_retrieval_scores.Fill(0)) &&
|
| | | (m_score_partials.Total() == 0 || m_score_partials.Fill(0)) &&
|
| | | (m_score_metrics.Total() == 0 || m_score_metrics.Fill(0)) &&
|
| | | (m_retrieval_partial.Total() == 0 || m_retrieval_partial.Fill(0)) &&
|
| | | (m_retrieval_merge.Total() == 0 || m_retrieval_merge.Fill(0)) &&
|
| | | (m_retrieval_top.Total() == 0 || m_retrieval_top.Fill(0)) &&
|
| | | (m_free_scores.Total() == 0 || m_free_scores.Fill(0)) &&
|
| | | (m_eviction_scores.Total() == 0 || m_eviction_scores.Fill(0)) &&
|
| | | (m_free_top.Total() == 0 || m_free_top.Fill(0)) &&
|
| | | (m_eviction_top.Total() == 0 || m_eviction_top.Fill(0)) &&
|
| | | (m_influence_partials.Total() == 0 || m_influence_partials.Fill(0)) &&
|
2026-08-20 22:59:48 +03:00 | | | (m_gradient_influence_partials.Total() == 0 || m_gradient_influence_partials.Fill(0)) &&
|
2026-08-20 19:55:53 +03:00 | | | (m_metric_partials.Total() == 0 || m_metric_partials.Fill(0)) &&
|
| | | (m_metrics.Total() == 0 || m_metrics.Fill(0)) &&
|
| | | (m_decision.Total() == 0 || m_decision.Fill(0)) &&
|
| | | (m_diagnostics_norm_partials.Total() == 0 || m_diagnostics_norm_partials.Fill(0)) &&
|
| | | (m_diagnostics_norms.Total() == 0 || m_diagnostics_norms.Fill(0)) &&
|
| | | (m_diagnostics_partials.Total() == 0 || m_diagnostics_partials.Fill(0)) &&
|
| | | (m_diagnostics_totals.Total() == 0 || m_diagnostics_totals.Fill(0))))
|
| | | ReturnFalse;
|
2026-08-18 19:58:41 +03:00 | | | return(SetCorrectionBuffer(GetPointer(m_selected_correction)));
|
| | | }
|
| | | #endif // NEURONET_D2SKILL_MQH
|
2026-09-04 17:39:51 +03:00 | | |
|