Pourquoi chercher la synergie ? Une métaheuristique unique fait un compromis : Differential Evolution (DE) explore largement (sa mutation vectorielle F.(r1-r2) fait de grands pas tant que la population est dispersee), Bare-Bones PSO (BBPSO) exploite localement (il echantillonne autour des meilleurs individus via une Gaussienne). Aucun des deux ne domine : DE trouve les bons bassins mais les affine mal ; BBPSO affine mais se piege s’il demarre dans un mauvais bassin. Le modèle insulaire heterogene – des iles DE et des iles BBPSO qui migrent – pourrait combiner les deux forces. Ou pas. Ce notebook le mesure, honnetement (on rapporte aussi les cas SANS synergie).
Definition operative. Il y a synergie quand la combinaison heterogene (DE+BBPSO) bat les deux constituants seuls (iles DE homogenes, iles BBPSO homogenes) a budget d’evaluations egal. C’est plus exigeant que « battre la moyenne » : il faut battre le meilleur des deux.
Components over metaphors (Sorensen 2015). DE et BBPSO ne sont pas invoques comme des boites noires metaphoriques : ce sont des composes geometriques du fork (DifferentialEvolution, BareBonesParticleSwarm), decomposes en primitives (mutation differentielle, echantillonnage Gaussien autour des leaders). On les assemble dans un IslandCompoundMetaheuristic – la composition est le sujet, pas l’etiquette. Suite de #1203, volet synergie de #3965.
On charge les DLLs du fork (self-contained via CopyLocalLockFileAssemblies : il embarque System.Drawing.Common.dll, SkiaSharp.dll + son binaire natif runtimes/<rid>/native/libSkiaSharp.dll). On precharge ce binaire natif (le #r manage ne cable pas le probing natif de SkiaSharp). Le sous-module est epingle sur le fork (pointeur 607cf7a), qui porte les composes geometriques (WOA/EO/FBI/DE/BBPSO), l’archipel heterogene (IslandCompoundMetaheuristic), le de-biais (ShiftedFitness / ShiftVectors.Seeded), l’overlay iles colorees (RenderHeatmapPng(..., individualColors)) et l’encodeur GIF anime (EncodeAnimatedGif).
Prerequis build.dotnet build ..\MetaGeneticSharp\src\MetaGeneticSharp.Extensions\MetaGeneticSharp.Extensions.csproj -c Debug (sous-module epingle sur le fork 607cf7a, rendu deterministe par pixel – PR MetaGeneticSharp #49).
// Fork DLLs loaded from the self-contained Extensions output (one-stop dir: it also ships// System.Drawing.Common.dll AND SkiaSharp.dll, needed at runtime by the graphic landscape types).#r "..\MetaGeneticSharp\src\MetaGeneticSharp.Extensions\bin\Debug\net9.0\GeneticSharp.Infrastructure.Framework.dll"#r "..\MetaGeneticSharp\src\MetaGeneticSharp.Extensions\bin\Debug\net9.0\GeneticSharp.Domain.dll"#r "..\MetaGeneticSharp\src\MetaGeneticSharp.Extensions\bin\Debug\net9.0\MetaGeneticSharp.Infrastructure.dll"#r "..\MetaGeneticSharp\src\MetaGeneticSharp.Extensions\bin\Debug\net9.0\MetaGeneticSharp.Domain.dll"#r "..\MetaGeneticSharp\src\MetaGeneticSharp.Extensions\bin\Debug\net9.0\MetaGeneticSharp.Extensions.dll"#r "..\MetaGeneticSharp\src\MetaGeneticSharp.Extensions\bin\Debug\net9.0\System.Drawing.Common.dll"#r "..\MetaGeneticSharp\src\MetaGeneticSharp.Extensions\bin\Debug\net9.0\SkiaSharp.dll"using MetaGeneticSharp;// IslandCompoundMetaheuristic, ShiftedFitness, ShiftVectors, SkiaLandscapeRendererusing GeneticSharp;// GA engine, selection/crossover/mutation, RandomizationProviderusing GeneticSharp.Extensions.Mathematic.Functions;// RastriginFitness, SchwefelFitnessusing System.Drawing;// Colorusing System.Runtime.InteropServices;// NativeLibrary, RuntimeInformation// .NET Interactive quirk: a #r to the managed SkiaSharp.dll does NOT wire up SkiaSharp's// runtimes/<rid>/native/ probing, so the first Skia call would P/Invoke a native lib that was// never loaded. We preload the arch-matching native binary from the self-contained output once.string rid = RuntimeInformation.ProcessArchitecture== Architecture.Arm64?"win-arm64": RuntimeInformation.ProcessArchitecture== Architecture.X86?"win-x86":"win-x64";NativeLibrary.Load($@"..\MetaGeneticSharp\src\MetaGeneticSharp.Extensions\bin\Debug\net9.0\runtimes\{rid}\native\libSkiaSharp.dll");Console.WriteLine("Wiring OK : MetaGeneticSharp + GeneticSharp + Extensions (composes DE/BBPSO + IslandCompound + ShiftedFitness + SkiaLandscapeRenderer + GIF).");
The below script needs to be able to find the current output cell; this is an easy method to get it.
Protocole : comparaison controlee a budget egal sur fonctions de-biaisees (dim 5)
Trois archipels de même structure (4 iles, migration SmallMigrationRate) – seul varie le contenu des iles :
Archipel
Iles
Rôle attendu
DE
4 iles Differential Evolution homogenes
exploration
BBPSO
4 iles Bare-Bones PSO homogenes
exploitation
DE+BBPSO
2 iles DE + 2 iles BBPSO
heterogene – l’hypothese de synergie
Chaque archipel est lance sur deux fonctions multimodales de-biaisees en dimension 5 (Rastrigin, Ackley – toutes deux a optimum a l’origine, relocalise hors centre via ShiftedFitness + ShiftVectors.Seeded), a budget d’evaluations identique. La dimension 5 (et non 2) est choisie pour que le problème soit assez dur pour que les opérateurs differentient : en dimension 2 a ce budget, tous solveent Rastrigin (objectif 0), ce qui rend une synergie indiscernable. La graine globale est fixee (FastRandomRandomization.ResetSeed(42)) au demarrage pour un depart reproductible – verifiee : double execution sur le moteur deterministe (MetaGeneticSharp #49) byte-identique sur les 7 cellules, le tableau ci-dessous et le GIF de la section Lecture reproduisent a l’octet pres.
Pourquoi de-biaiser ? Rastrigin et Ackley ont leur optimum a l’origine ; un opérateur « recentre » y serait flate. ShiftedFitness translate l’optimum d’un vecteur non nul (magnitude 0.15 de la plage, assez petite pour garder l’optimum dans les bornes) : la recherche doit le suivre, pas tomber dessus par biais de centre.
Caveats honnetes. (1) Graine unique : ce notebook est reproductible (même graine -> même sortie) mais n’est pas un banc multi-graines ; les trois archipels se succedent sur le même flux aleatoire (departs equitables mais non identiques). Un banc multi-graines + fonctions rotees (style CEC) rigoureux est l’item #3963 – pre-requisdeclare du volet synergie. (2) La coloration par ile du GIF (section suivante) suppose les individus ranges contigument par ile (précédent MGS-4) ; la migration peut alterer cet ordre. (3) Le GIF est une illustration 2D ; le banc de mesure est en dim 5.
// Graine globale fixee AVANT tout acces au generateur -> depart reproductible (run1 == run2).FastRandomRandomization.ResetSeed(42);IFitness rastrigin =newRastriginFitness();IFitness ackley =newAckleyFitness();var(raLo, raHi)= KnownFunctionsBounds.For(typeof(RastriginFitness));var(aLo, aHi)= KnownFunctionsBounds.For(typeof(AckleyFitness));// De-biais : optimum relocalise hors centre (magnitude 0.15 de la plage -> reste dans les bornes).double[] raShift = ShiftVectors.Seeded(5,0.15*(raHi - raLo), seed:11);double[] ackShift = ShiftVectors.Seeded(5,0.15*(aHi - aLo), seed:17);var raFit =newShiftedFitness(rastrigin, raShift);var ackFit =newShiftedFitness(ackley, ackShift);string[] configs ={"DE","BBPSO","DE+BBPSO"};var results =new List<(string Fn,string Cfg,double Best)>();var problems =new(string, IFitness,(double,double))[]{("Rastrigin shifte (dim 5)", raFit,(raLo, raHi)),("Ackley shifte (dim 5)", ackFit,(aLo, aHi))};foreach(var(fn, fit, b)in problems)foreach(var cfg in configs) results.Add((fn, cfg,RunIsland(cfg, fit, b, dim:5, Gens)));// Verdict : fitness = objectif negatif (max = meilleur). Synergie = DE+BBPSO > max(DE, BBPSO).Console.WriteLine($"{"Fonction",-26}{"Config",-12}{"Fitness(max)",-16}{"Objectif",-12}");Console.WriteLine(newstring('-',66));var summary =new List<(string Fn,bool Synergy,double Mix,double BestConstituent)>();foreach(var fn innew[]{"Rastrigin shifte (dim 5)","Ackley shifte (dim 5)"}){var rows = results.Where(v => v.Fn== fn).ToList();foreach(var r in rows) Console.WriteLine($"{r.Fn,-26}{r.Cfg,-12}{r.Best,-16:F4}{-r.Best,-12:F4}");double de = rows.First(r => r.Cfg=="DE").Best;double bb = rows.First(r => r.Cfg=="BBPSO").Best;double mix = rows.First(r => r.Cfg=="DE+BBPSO").Best;bool syn = mix > Math.Max(de, bb); summary.Add((fn, syn, mix, Math.Max(de, bb))); Console.WriteLine($" -> {(syn ? "SYNERGIE" : "PAS de synergie")} sur {fn} : DE+BBPSO ({mix:F4}) vs meilleur constituant ({Math.Max(de, bb):F4})"); Console.WriteLine();}int synergies = summary.Count(s => s.Synergy);Console.WriteLine($"Bilan : {synergies}/{summary.Count} fonctions montrent une synergie (DE+BBPSO bat les DEUX constituants).");
Fonction Config Fitness (max) Objectif
------------------------------------------------------------------
Rastrigin shifte (dim 5) DE -1,8562 1,8562
Rastrigin shifte (dim 5) BBPSO -19,8004 19,8004
Rastrigin shifte (dim 5) DE+BBPSO -3,9393 3,9393
-> PAS de synergie sur Rastrigin shifte (dim 5) : DE+BBPSO (-3,9393) vs meilleur constituant (-1,8562)
Ackley shifte (dim 5) DE -1,6819 1,6819
Ackley shifte (dim 5) BBPSO -0,6319 0,6319
Ackley shifte (dim 5) DE+BBPSO -2,2376 2,2376
-> PAS de synergie sur Ackley shifte (dim 5) : DE+BBPSO (-2,2376) vs meilleur constituant (-0,6319)
Bilan : 0/2 fonctions montrent une synergie (DE+BBPSO bat les DEUX constituants).
Lecture du verdict : pas de synergie – un résultat negatif honnete
Le banc est sans appel : sur les deux fonctions de-biaisees en dim 5, l’archipel heterogene DE+BBPSO est battu par le meilleur de ses constituants homogenes. Synergie : 0/2.
Fonction (dim 5)
DE (explorateur)
BBPSO (exploiteur)
DE+BBPSO (heterogene)
Qui gagne ?
Rastrigin shifte
1,86
19,80
3,94
DE seul
Ackley shifte
1,68
0,63
2,24
BBPSO seul
(Objectif = fitness negativ, plus petit = meilleur ; optimum 0.)
Ce que les chiffres disent. - Rastrigin (foret reguliere de minima locaux) recompense l’exploration : DE seul (1,86) domine largement BBPSO (19,80, piege dans un minimum local). Ajouter des iles BBPSO a DE (3,94) degrade DE : les iles exploitatrices, coincees, envoient leurs mauvais individus a DE par migration. - Ackley (cratere central + ondulations) recompense au contraire l’echantillonnage Gaussien de BBPSO (0,63, le meilleur). Melanger (2,24) degrade les deux : ni la rupture de DE ni le raffinement de BBPSO ne s’imposent, la migration moyenne les affaiblit.
La lecon (falsifiable, pas doctrinale). La synergie d’iles heterogenes n’est pas automatique. Combiner un bon explorateur et un bon exploiteur avec la migration par defaut peut propager les solutions piegees d’un opérateur vers l’autre et produire un compromis inferieur au meilleur constituant. Pour qu’une synergie apparaisse, il faut probablement des opérateurs dont les forces sont complementaires sur le paysage considere et une migration accordee (ex. migrer seulement les meilleurs, ou par regimes temporels). Les exercices ci-dessous explorent ces pistes (WOA+EO, migration desactivee, Ackley additionnel).
Ce résultat negatif est aussi informatif qu’une synergie confirmee : il montre que la composition n’est pas une recette magique – comme l’etablit la critique « components over metaphors » (Sorensen 2015), la valeur d’une combinaison se demontre, elle ne se decrete pas. Le banc rigoureux multi-graines + rote (#3963) est necessaire pour confirmer ou infirmer ce verdict sur une suite plus large.
// GIF multicolore : archipel DE+BBPSO heterogene trace generation par generation sur Rastrigin shifte (2D, illustration).// Chaque individu est colore par son ile (DE = DarkOrange, BBPSO = ForestGreen) -> la repartition// exploration (iles DE dispersees) / exploitation (iles BBPSO resserrees) devient visible dans le temps.// Note : illustration 2D (le banc de mesure ci-dessus est en dim 5).FastRandomRandomization.ResetSeed(42);double[] raShift2D = ShiftVectors.Seeded(2,0.30*(raHi - raLo), seed:11);// shift 2D realisable (optimum reste dans [-5.12, 5.12])var raFit2D =newShiftedFitness(rastrigin, raShift2D);Func<double[],double> raField = c => raFit2D.Evaluate(newDoubleArrayChromosome(c, raLo, raHi));List<(int gen, List<double[]> pop)>TraceIslands(IFitness fit,(double lo,double hi) b,int gens, ISet<int> snaps){double mid =0.5*(b.lo+ b.hi);var adam =newDoubleArrayChromosome(new[]{ mid, mid }, b.lo, b.hi);var pop =newMetaPopulation(PopSize, PopSize, adam);var ga =newMetaGeneticAlgorithm(pop, fit,newEliteSelection(),newUniformCrossover(0.5f),newUniformMutation(true),BuildIslands("DE+BBPSO", gens)); ga.Termination=newGenerationNumberTermination(gens);var trace =new List<(int, List<double[]>)>();int g =0; ga.GenerationRan+=(s, e)=>{ g++;if(!snaps.Contains(g))return; trace.Add((g, ga.Population.CurrentGeneration.Chromosomes.Select(c =>((DoubleArrayChromosome)c).GetDoubleValues()).ToList()));}; ga.Start();return trace;}var snaps =new HashSet<int>(new[]{1,5,10,18,28,40,55,72});var trace =TraceIslands(raFit2D,(raLo, raHi), gens:72, snaps);// Couleur par ile (hypothese : individus ranges contigument par ile, precedent MGS-4) :// iles 0,1 = DE (DarkOrange) ; iles 2,3 = BBPSO (ForestGreen). 4 iles * PopSize/4 = 10 chacune.int perIsland = PopSize /4;var islandColors =new Color[PopSize];for(int i =0; i < PopSize; i++) islandColors[i]=(i / perIsland <2)? Color.DarkOrange: Color.ForestGreen;var gifFrames =new List<byte[]>(trace.Count);foreach(var(gen, pop)in trace){double[] best = pop.OrderByDescending(p =>raField(p)).First(); gifFrames.Add(SkiaLandscapeRenderer.RenderHeatmapPng( raField,(raLo, raHi),(raLo, raHi), width:360, height:270, population: pop, best: best, individualColors: islandColors));}byte[] gif = SkiaLandscapeRenderer.EncodeAnimatedGif(gifFrames, delayCentiseconds:40, loopCount:0, maxColors:64);display(HTML($"<figure style='margin:6px 0'>"+ $"<img src='data:image/gif;base64,{Convert.ToBase64String(gif)}' style='width:380px;image-rendering:pixelated;border:1px solid #ccc'/>"+ $"<figcaption style='font:12px sans-serif;color:#555'>Archipel DE+BBPSO sur Rastrigin shifte -- <span style='color:DarkOrange'>iles DE (orange, exploration)</span> et <span style='color:ForestGreen'>iles BBPSO (vert, exploitation)</span> ; la migration fait coalescer le nuage vers le minimum global (deplace hors du centre).</figcaption></figure>"));Console.WriteLine($"GIF synergie : {gifFrames.Count} frames, {gif.Length / 1024.0:F1} KB (image/gif, lisible sur le viewer statique GitHub).");
Archipel DE+BBPSO sur Rastrigin shifte -- iles DE (orange, exploration) et iles BBPSO (vert, exploitation) ; la migration fait coalescer le nuage vers le minimum global (deplace hors du centre).
GIF synergie : 8 frames, 238,9 KB (image/gif, lisible sur le viewer statique GitHub).
Conclusion : la synergie se demontre, elle ne se decrete pas
La question n’etait pas « les métaheuristiques combinees sont-elles magiquement meilleures ? » mais une question falsifiable : sur des fonctions de-biaisees, a budget egal, l’archipel heterogene DE+BBPSO bat-il ses deux constituants homogenes ? Le banc ci-dessus y repond chiffres a l’appui – et la reponse honnete peut etre non (auquel cas la combinaison n’apportait rien sur ces fonctions, une information aussi utile qu’une synergie confirmee).
Ce que ce notebook etablit (methodologiquement) : - un protocole contrôle (même structure d’archipel, budget egal, fonctions de-biaisees) ou l’heterogeneite est l’unique variable ; - un verdict mesurable (synergie = battre le meilleur constituant, pas la moyenne) ; - une visualisation multicolore (overlay individualColors + GIF anime) qui rend la repartition exploration/exploitation visible generation par generation.
Limites honnetes (reprises du protocole) : graine unique (pas un banc multi-graines), de-biais vectoriel seulement (pas de rotation CEC), coloration par ile supposee contigue. Le banc rigoureux multi-graines + rote est l’item #3963 – pre-requisdeclare du volet synergie. Le present notebook est la demonstration du protocole + du visuel ; le banc exhaustif est le suivi.
Liens
MGS-4 Islands – le modèle insulaire (dont est tire l’overlay iles colorees)
Convention : cellules a completer. Squelette fourni. Ne pas lever d’erreur – utiliser // TODO / Console.WriteLine / return. Les helpers BuildIslands, RunIsland, MakeDE, MakeBBPSO, raFit, swFit, raLo/raHi, swLo/swHi sont définis plus haut.
Exercice 1 : une autre paire complementaire (WOA explorateur + EO exploiteur)
DE/BBPSO n’est qu’une paire. WOA (contrôle de flux geometrique, forte exploration globale) et EO (convergence vers les candidats d’equilibre, exploitation) sont une autre paire complementaire. Objectif : construire un archipel heterogene 2 WOA + 2 EO (via BuildIslands-like), le lancer sur Rastrigin shifte, et comparer au verdict DE+BBPSO – laquelle produit une synergie ?
// Exercice 1 : archipel heterogene WOA + EO sur Rastrigin shifte, comparaison au verdict DE+BBPSO.// A COMPLETER. Le notebook s'execute de bout en bout meme si l'exercice n'est pas fait.// TODO etudiant : construire 2 iles WOA + 2 iles EO (cf BuildIslands, en remplaçant DE/BBPSO par// new WhaleOptimisationAlgorithm { MaxGenerations=Gens, GeometricConverter=DoubleIdentityConverter(), NoMutation=true }// new EquilibriumOptimizer { MaxGenerations=Gens, GeometricConverter=DoubleIdentityConverter(), NoMutation=true }// puis RunIsland-like sur raFit, comparer a la ligne DE+BBPSO du verdict.Console.WriteLine("Exercice 1 a completer : archipel heterogene WOA+EO vs DE+BBPSO sur Rastrigin shifte.");
Exercice 1 a completer : archipel heterogene WOA+EO vs DE+BBPSO sur Rastrigin shifte.
Exercice 2 : la migration est-elle necessaire a la synergie ?
La synergie (si elle apparait) vient-elle de l’heterogeneite seule ou de la migration entre iles ? Objectif : desactiver la migration (ic.MigrationMode = MigrationMode.None, cf Islands5BestMixtureNoMigration) sur l’archipel DE+BBPSO et relancer – la synergie tient-elle sans echange entre iles ?
// Exercice 2 : synergie DE+BBPSO SANS migration (MigrationMode.None), comparer au verdict avec migration.// A COMPLETER. Le notebook s'execute de bout en bout meme si l'exercice n'est pas fait.// TODO etudiant : variante de BuildIslands("DE+BBPSO", g) avec ic.MigrationMode = MigrationMode.None// avant ic.Build(), lancer sur raFit + swFit, comparer au verdict ci-dessus.Console.WriteLine("Exercice 2 a completer : synergie DE+BBPSO sans migration -- tient-elle ?");
Exercice 2 a completer : synergie DE+BBPSO sans migration -- tient-elle ?
Exercice 3 : une troisieme fonction de-biaisee (Ackley shifte)
Le verdict sur 2 fonctions est un debut. Objectif : ajouter AckleyFitness (cratere central + ondulations concentriques, fortement multimodale) de-biaisee via ShiftedFitness, lancer les 3 archipels, et dire si la synergie (ou son absence) se generalise a une troisieme topologie.
// Exercice 3 : ajouter AckleyFitness shiftee au banc, lancer les 3 archipels, verdict sur 3 fonctions.// A COMPLETER. Le notebook s'execute de bout en bout meme si l'exercice n'est pas fait.// TODO etudiant :// IFitness ack = new AckleyFitness();// var (aLo, aHi) = KnownFunctionsBounds.For(typeof(AckleyFitness));// double[] aShift = ShiftVectors.Seeded(2, 0.30 * (aHi - aLo), seed: 23);// var ackFit = new ShiftedFitness(ack, aShift);// ... lancer DE / BBPSO / DE+BBPSO via RunIsland, etendre le verdict.Console.WriteLine("Exercice 3 a completer : verdict synergie etendu a Ackley shiftee (3 fonctions).");
Exercice 3 a completer : verdict synergie etendu a Ackley shiftee (3 fonctions).