Skip to content

feat(backtester,#7357): porter le corps SVM a noyau (tranche 4) - #14369

Merged
myia-ai-01 merged 1 commit into
mainfrom
feature/c871-svm-tranche4
Sep 2, 2026
Merged

myia-ai-01 merged 1 commit into
mainfrom
feature/c871-svm-tranche4

Conversation

@jsboige

@jsboige jsboige commented Sep 2, 2026 •

Copy link
Copy Markdown
Owner

Grain: DEEP/qc — lane myia-po-2024:CoursIA-2 — prev: DEEP/training #14359

Summary

Tranche 4 de l'EPIC #7357 : porter le corps de TradingSvmModelConfig, laissé en stub explicite par la tranche 3 (#13858, qui le nommait lui-même « tranche 4 »). TrainModel entraîne désormais un vrai SVM à noyau au lieu de lever ApplicationException.

Porté depuis le fork MyIntelligenceAgency/Lean@612dddf9, chemin MyIA.Trading.Backtester/TradingSvmModelConfig.cs : ClassifierTradingModel, SvmTradingModel, GetKernel, cache statique _CachedModels, TrainModelInternal, SvmBenchmark, CalibrateComplexity.

Le grain consistait à porter le corps, pas à choisir la lib — mais une contradiction documentée devait être tranchée d'abord (voir ci-dessous).

Verdict SOTA : SOTA-OK — aucune substitution

Trois sources du dépôt annonçaient une substitution « Accord → ML.NET/sklearn » : le commentaire du stub, l'en-tête du .csproj (ligne 8), et backtester-e2-cadrage.md §44 (« un gap : candidats SharpLearning ou LibSVM-sharp »). Mesure faite, elle est sans objet :

  • ML.NET n'expose pas de SVM à noyau. La substitution annoncée n'avait pas de cible.
  • Accord.NET 3.8.2-alpha — la version du fork — tourne tel quel sur net9.0. Sonde dédiée épinglant exactement l'API du corps upstream (MulticlassSupportVectorLearning<IKernel> + Learner lambda + teacher.Learn) : La génération a réussi. 0 Avertissement(s) 0 Erreur(s), puis exécution UPSTREAM-API-OK error=0,000. Pas de NU1701 (le shim de compat rapporté pour la 2.6.0 est absent en 3.8.2-alpha).

Pourquoi pas la 2.6.0 de #12545. #12545 porte bien le verdict SOTA-OK « SVM à noyau en .NET » et supersède #12541 — la question de la lib était donc déjà tranchée en faveur d'Accord. Mais il valide la 2.6.0, dont l'API est la génération précédente (KernelSupportVectorMachine(IKernel, inputs) + SequentialMinimalOptimization(svm, X, y).Run()). Les deux ne sont pas interchangeables : la 2.6.0 aurait imposé de réécrire le corps au lieu de le porter. La 3.8.2-alpha le compile verbatim.

L'en-tête du .csproj et le commentaire du stub sont corrigés dans ce diff. backtester-e2-cadrage.md §44 reste à reprendre — voir Résiduel.

Trois écarts délibérés avec l'upstream

Tous documentés en tête de TradingSvmModelConfig.cs, aucun silencieux.

1. using DotNetNuke.Services.Log.EventLog supprimé. Mesuré : 1 seule occurrence dans le fichier upstream (le using lui-même), zéro usage dans le corps. C'est exactement l'abandon des 6 DLL Aricie PKP prescrit par l'Option C (décision user 2026-07-19).

2. Ordre des membres de KnownKernel conservé. L'upstream place TStudent2 en 2ᵉ ; main l'a en 4ᵉ depuis la tranche 3. L'ordre de main est conservé : réordonner changerait la valeur entière de chaque membre pour toute config déjà sérialisée, et le ferait sans bruit. Un test épingle les quatre ordinaux.

3. CalibrateComplexity réparé — un défaut upstream, pas un choix de style.

Le bloc sous limite de temps upstream remplace teacher au lieu d'appeler Learn :

() => { try { teacher = new MulticlassSupportVectorLearning<IKernel>(); } catch { } }

Conséquence en chaîne : machine reste null → machine.Decide(xTrain) lève une NRE → avalée par le catch englobant → testError ne quitte jamais double.MaxValue → testError < currentResult est toujours faux → bestComplexity ne bouge jamais. La méthode rend TOUJOURS son amorce 0.0001, pendant que l'appelant journalise SVM complexity calibrated: 0.0001.

Ce n'est pas une déduction : une réplique verbatim du corps upstream a été exécutée côte à côte avec le corps réparé, sur les mêmes données —

jeu corps réparé corps upstream
XOR net (n=64) 0.0001 0.0001
XOR bruité spread 0.9 (n=80) 0.00374 0.0001
XOR bruité spread 1.1 (n=120) 706.88 0.0001
XOR bruité spread 1.1 (n=240) 15.79 0.0001

Porter ce corps verbatim aurait livré une fonction dont le nom et le message de log affirment une calibration qu'elle est incapable d'effectuer. L'appel d'entraînement est rétabli et l'absence de modèle traitée explicitement au lieu d'être masquée par une NRE. Le défaut upstream est signalé à part — voir Résiduel.

Validation

dotnet build du projet : 0 erreur, 5 avertissements tous préexistants (MyIA.Trading.Converter, TradingTrainingDataConfig) — aucun sur le fichier porté, aucun NU1701.

dotnet test MyIA.Trading.Backtester.Tests : 19/19 verts (48 s), re-lancé après le rebase sur aaa9f873.

Chaque assertion positive est appariée à une mutation qui doit la faire tomber. Un contrôle qu'on n'a pas vu échouer ne contrôle rien :

  • SvmTradingModel_LearnsXorAndPredictsThroughTradingModelWrapper — XOR, erreur 0, décisions vérifiées échantillon par échantillon à travers l'enveloppe ITradingModel portée.
  • LinearKernel_FailsOnXor_... — mutation de contrôle : mêmes données, même pipeline, même complexité, seul le noyau change. L'erreur doit être non nulle. Sans ce négatif, le test précédent serait compatible avec un problème dégénéré (Prong B).
  • GetKernel_... (×2) — chaque membre → son noyau Accord, degrés annoncés par le nom, membre hors domaine qui lève, et le compte des membres épinglé pour qu'un ajout non couvert fasse rougir.
  • KnownKernel_OrdinalsArePinned_... — écart 2.
  • CalibrateComplexity_ActuallyExploresAndDoesNotReturnItsSeedValue — garde de régression de l'écart 3.
  • CalibratedComplexity_ScoresBetterThanTheSeedComplexity — la calibration améliore ce qu'elle optimise : score TestModel −49 au C calibré contre −33 à l'amorce (plus bas = meilleur).

La garde de l'écart 3 est posée là où elle discrimine, et c'est une mesure, pas une supposition. Ma première version la posait sur un XOR net : elle a échoué, et l'enquête a montré qu'elle ne pouvait pas réussir — sur XOR net, C=0.0001 classe déjà parfaitement (erreur 0 à tous les C testés), donc conserver l'amorce y est le bon résultat, et les deux corps rendent 0.0001. La garde est déplacée sur un XOR à paquets chevauchants, où les deux corps divergent (706.88 vs 0.0001). Le bruit est déterministe et portable (pas System.Random, dont l'algorithme n'est pas garanti stable entre runtimes) : deux exécutions rendent la même valeur au bit près.

Deux tests de la tranche 3 assertaient que le stub lève : ils sont remplacés, pas supprimés. TradingTrainingConfig_DelegatesToCurrentModelConfig prouve désormais l'aiguillage sur GetModelName, qui emprunte le même CurrentModelConfig et reste déterministe.

Périmètre

4 fichiers, tous dans le scope claimé (paths: MyIA.Trading.Backtester/**, MyIA.Trading.Backtester.Tests/**) :

  • MyIA.Trading.Backtester/TradingSvmModelConfig.cs — le port (+486/−13)
  • MyIA.Trading.Backtester/MyIA.Trading.Backtester.csproj — 4 PackageReference Accord 3.8.2-alpha + en-tête corrigé
  • MyIA.Trading.Backtester.Tests/TradingSvmModelConfigTests.cs — nouveau, 8 tests
  • MyIA.Trading.Backtester.Tests/TradingModelsConfigTests.cs — 2 tests du stub remplacés

Catalogue byte-identique à main. Aucun notebook touché.

Résiduel (ne bloque pas ce diff, à ouvrir en suivi)

  1. Défaut upstream CalibrateComplexity — le fork MyIntelligenceAgency/Lean porte toujours le corps qui ne calibre pas. Issue de suivi à ouvrir : le dépôt CoursIA est réparé, l'amont ne l'est pas.
  2. docs/reference/backtester-e2-cadrage.md §44 — « le noyau gaussien est un gap : candidats SharpLearning ou LibSVM-sharp » est périmé par cette mesure. Hors périmètre claimé de cette PR (fichier docs/), à reprendre dans la tranche suivante ou une PR dédiée.
  3. Tranche 5 — BackTesting.cs reste à porter : l'EPIC n'est pas résolue, d'où See et non Closes.

Base rouge (non réparable par cette lane)

Le build de MyIA.CoursIA.sln échoue avec 9 erreurs distinctes dans MyIA.AI.Notebooks/GenAI/** — 8 × CS1513 (« } attendue », SemanticKernel/*.cs) et 1 × CS9298 (apphost.cs : « les directives #: ne peuvent être utilisées que dans des programmes basés sur des fichiers »).

Correction d'un chiffre que j'avais donné plus tôt dans ce cycle. J'avais écrit « 13 erreurs » : ce nombre ne correspondait à aucune agrégation défendable. Le log en contient 26 occurrences, parce que plusieurs projets incluent les mêmes fichiers et que MSBuild réémet l'erreur une fois par projet ; dédupliqué sur (fichier, ligne, colonne, code), le compte stable est 9. Les deux nombres se mesurent, 13 ne se mesurait pas — je le retire plutôt que de le raccommoder.

Aucun rapport avec cette PR, et c'est vérifié dans les deux sens : git diff --name-only origin/main...HEAD ne rend 0 fichier sous MyIA.AI.Notebooks/, et git status --porcelain y rend 0 ligne. Ces fichiers sont donc byte-identiques à main dans mon worktree — le rouge y est préexistant. Corrobore la base-rouge déjà observée sur #14313, #14316, #14317, #14322, #14330, #14340, #14348, #14349, #14355. Signalé au coordinateur, pas réparable depuis cette lane.

See #7357

Remplace le stub explicite de TradingSvmModelConfig.TrainModel par le corps
upstream du fork MyIntelligenceAgency/Lean (612dddf9) : ClassifierTradingModel,
SvmTradingModel, GetKernel, cache statique, TrainModelInternal, SvmBenchmark et
CalibrateComplexity.

Substitution : AUCUNE. Le cadrage (geste 2) anticipait un remplacement Accord ->
ML.NET/sklearn ; mesure faite, il est sans objet — ML.NET n'expose pas de SVM a
noyau, et Accord.NET 3.8.2-alpha (la version du fork) restore, compile le corps
verbatim et s'execute sur net9.0 avec 0 avertissement et pas de NU1701. La
2.6.0 validee par #12545 expose l'API precedente (KernelSupportVectorMachine +
SequentialMinimalOptimization(...).Run()) et aurait impose une reecriture.

Trois ecarts deliberes, documentes en tete de fichier :
1. `using DotNetNuke.Services.Log.EventLog` supprime (0 usage dans le corps) —
   abandon des DLL Aricie PKP, Option C tranchee le 2026-07-19.
2. Ordre des membres de KnownKernel : celui deja committe en tranche 3, pas
   celui de l'upstream. Reordonner changerait silencieusement les valeurs
   entieres de toute config deja serialisee (test d'epinglage ajoute).
3. CalibrateComplexity repare. Le bloc sous limite de temps upstream remplacait
   `teacher` au lieu d'appeler Learn : `machine` restait null, la NRE etait
   avalee, testError ne quittait jamais double.MaxValue et la methode rendait
   TOUJOURS son amorce 0.0001 — sous un log affirmant « SVM complexity
   calibrated ». Mesure cote a cote sur le meme jeu : upstream 0.0001, repare
   706.88.

Tests : 19/19 verts. Chaque assertion positive est appariee a une mutation qui
ne change QUE le champ teste et doit la faire tomber (noyau lineaire sur XOR).
La garde de l'ecart 3 est posee sur un XOR a paquets chevauchants, parce que
sur un XOR net les deux corps rendent 0.0001 et la garde serait aveugle.

See #7357

Co-Authored-By: Claude-Code <noreply@anthropic.com>

@jsboige jsboige left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Hermes] — verification firsthand au head 69a5d9de9f (0 review cluster pré-existante sur ce SHA) :

  • Issue-first match (#7357) : le grain demandé (« tranche 4 = corps TradingSvmModelConfig, porter le corps, pas choisir la lib ») est exactement ce qui est livré. La divergence de version avec le verdict #12545 (2.6.0 → 3.8.2-alpha) est explicite et mesurée, pas une substitution silencieuse : l'argument (2.6.0 = génération d'API précédente qui imposerait une réécriture ; 3.8.2-alpha compile le corps verbatim, 0 NU1701) est corroboré dans le diff — l'en-tête du csproj et le commentaire stub sont corrigés en conséquence, et le doc SOTA référencé (backtester-e2-svm-kernel.md) existe bien sur main.
  • Périmètre : 4 fichiers dans le diff = les 4 annoncés au body. Pas d'accumulateur.
  • Écart 3 (CalibrateComplexity) : l'analyse du défaut upstream est cohérente avec le code porté — teacher.Learn rétabli dans le bloc ExecuteWithTimeLimit, machine == null → maxedOut explicite au lieu d'une NRE avalée. La garde CalibrateComplexity_ActuallyExplores... est posée sur le jeu où elle discrimine (XOR chevauchant), et la paire positive/mutation est réelle (LinearKernel_FailsOnXor prouve que c'est le noyau qui porte le résultat).
  • Security scan : 0 match sur le diff. Ordinaux KnownKernel épinglés par test (écart 2, ordre de main conservé) ✓.
  • Note mineure : le body annonce « TradingSvmModelConfigTests.cs — nouveau, 8 tests » ; décompte réel dans le diff = 7 [Fact]. Écart de comptage sans conséquence (les claims 19/19 verts portent sur la suite entière), à corriger dans le body pour la traçabilité.

Fond solide — écarts délibérés documentés, chaque assertion positive appariée à sa mutation, pas de silences. (contrainte token : COMMENT only, opener jsboige)

@myia-ai-01
myia-ai-01 merged commit 90a7446 into main Sep 2, 2026
14 checks passed
myia-ai-01 pushed a commit that referenced this pull request Sep 4, 2026
…teComplexity (#14522)

Codifie la divergence intentionnelle avec l'amont MetaGeneticSharp : commentaire XML + section de doc renvoyant a l'issue upstream MyIntelligenceAgency/Lean#40, avec sa condition de fin ecrite.

Deux fichiers, aucun code de production touche. Les deux gardes de non-regression sont deja sur main depuis #14369.

Le rouge prev_guard de cette PR etait un faux positif d'organe : le garde evalue le corps entier, donc la phrase qui documentait le tag de #14538 comptait comme une seconde declaration prev: pointant #14522 depuis #14522. Corrige par une edition de 8 caracteres en prose ; le tag (prev: LIGHT/guard #14459, mergee) n'a jamais eu besoin d'etre touche. Defaut d'organe trace en #14550.

Grain: MED/qc -- lane myia-po-2023:CoursIA-2

See #14370
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants