MGS-7c : Rosenbrock (vallée étroite) + Griewank (produit-cosinus) en projection N-D

← MGS-7b LandscapeMultidim · MGS-8 LandscapeExplorer →

Pourquoi Rosenbrock et Griewank ?

MGS-7b a couvert les quatre fonctions classiques du banc CEC : Sphère (c.732), Rastrigin (c.732), Schwefel (c.732), Ackley (c.785).

Restent deux fonctions au comportement structurellement différent que la projection N-D doit affronter :

  1. Rosenbrock \(f(\vec x) = -\sum_{i=1}^{n-1} \left(100(x_{i+1} - x_i^2)^2 + (1-x_i)^2\right)\) — la vallée-courbe-étroite banane. L’optimum est dans \(x_i \approx 1\), mais la trajectoire de descente est piégée dans un couloir de largeur \(\sim 10^{-2}\). Recommandé \([-2.048, 2.048]\).

  2. Griewank \(f(\vec x) = \frac{1}{4000}\sum_i x_i^2 - \prod_i \cos\left(\frac{x_i}{\sqrt{i}}\right) + 1\) — le produit-cosinus-haute-fréquence. Contrairement à Ackley (somme de cosinus), Griewank multiplie des cosinus à fréquences décroissantes : \(\cos(x_0)\), \(\cos(x_1/\sqrt{2})\), \(\cos(x_2/\sqrt{3})\), etc. Échelle large \([-600, 600]\).

Ce que ce notebook teste

Question pédagogique : la projection MAX (cf MGS-7b cellule RenderHeatmap N-D, port #7483) gomme-t-elle les structures fines de Rosenbrock (vallée 1-pixel-large) plus vite que celles d’Ackley (bassine large multi-pixels) ? Et comment Griewank se distingue-t-il de Ackley en 2-D alors que les deux reposent sur du cosinus ?

Anti-pattern INTRINSIC documenté : si la heatmap Griewank-n=30 devient quasi-uniforme, c’est une signature de la projection MAX (le produit de cosinus à fréquences décroissantes s’aplatit sous MAX), pas un bug de la projection. Cf L785-L2 ★.

Reproductibilité

Les seeds utilisées (42, 7, 99) sont explicites dans les cellules. Les heatmaps sont générées via le moteur KnownFunctionLandscape.RenderHeatmap du submodule MetaGeneticSharp.Extensions (port PR #7583 + #7776).

#r "..\MetaGeneticSharp\src\MetaGeneticSharp.Extensions\bin\Debug\net9.0\MetaGeneticSharp.Extensions.dll"

using MetaGeneticSharp;
using GeneticSharp;

// Verifier l'API du submodule -- check BLOQUANT. Le porteur des bornes est
// KnownFunctionsBounds.For (KnownFunctions.cs), unique point d'acces canonique.
var boundsFor = typeof(KnownFunctionsBounds).GetMethod("For",
    System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
if (boundsFor is null)
    throw new InvalidOperationException(
        "KnownFunctionsBounds.For absent du submodule -- recompiler MetaGeneticSharp.Extensions");
var rosenbrockType = System.Type.GetType("MetaGeneticSharp.RosenbrockFitness, MetaGeneticSharp.Extensions");
var griewankType = System.Type.GetType("MetaGeneticSharp.GriewankFitness, MetaGeneticSharp.Extensions");
if (rosenbrockType is null || griewankType is null)
    throw new InvalidOperationException(
        "Classes de fitness introuvables dans MetaGeneticSharp.Extensions");
Console.WriteLine($"KnownFunctionsBounds.For present: {boundsFor is not null}");
Console.WriteLine($"RosenbrockFitness charge: {rosenbrockType.FullName}");
Console.WriteLine($"GriewankFitness charge: {griewankType.FullName}");

// Affichage des bornes en culture invariante (separateur decimal point,
// independant des reglages de la machine hote).
var fmt = "0.###";
var fmt4 = "0.####";
var invCulture = System.Globalization.CultureInfo.InvariantCulture;
// Echelles recommandees : mesurees par l'appel REEL au submodule (KnownFunctions.cs:236),
// pas recopiees en litteral.
var (rosenbrockMin, rosenbrockMax) = KnownFunctionsBounds.For(rosenbrockType);
var (griewankMin, griewankMax) = KnownFunctionsBounds.For(griewankType);
Console.WriteLine($"Rosenbrock: range [{rosenbrockMin.ToString(fmt, invCulture)}, {rosenbrockMax.ToString(fmt, invCulture)}] (KnownFunctionsBounds.For)");
Console.WriteLine($"Griewank:   range [{griewankMin.ToString(fmt, invCulture)}, {griewankMax.ToString(fmt, invCulture)}] (KnownFunctionsBounds.For)");
KnownFunctionsBounds.For present: True
RosenbrockFitness charge: MetaGeneticSharp.RosenbrockFitness
GriewankFitness charge: MetaGeneticSharp.GriewankFitness
Rosenbrock: range [-2.048, 2.048] (KnownFunctionsBounds.For)
Griewank:   range [-600, 600] (KnownFunctionsBounds.For)

Rosenbrock en \(n = 2, 5, 30\) : la vallée diagonale disparaît

En 2-D, Rosenbrock dessine une vallée étroite en banane qui serpente du coin supérieur-gauche \((-2, 4)\) environ jusqu’au point optimal \((1, 1)\). La heatmap est asymétrique : le coin \((x_1, x_2) = (-2, 4)\) est plus rouge (vallée en pente descendante raide) que le coin symétrique \((4, -2)\).

En 30-D, chaque pixel \((x_1, x_2)\) doit explorer 28 dimensions cachées via MAX-projection. Comme la vallée est étroite (largeur \(\sim 10^{-2}\)), la probabilité qu’un sample aléatoire tombe dans la vallée est faible — la MAX-projection retient donc presque toujours une fitness hors vallée, et la heatmap devient quasi-uniforme rouge-orange ; mesuré sur le rendu déterministe, le bleu s’effondre (moy(B)=1,4) dans un champ orange-vert structuré (#12457 puis MetaGeneticSharp #49). C’est la signature : Rosenbrock est plus vulnérable à la projection MAX qu’Ackley (dont la bassine large multi-pixels survit mieux).

using System.IO;
using System.Security.Cryptography;
// Piege #12457 : un unique Random etatique partage entre les dimensions rend
// d30 quasi-confondu a d2. RNG independant par dimension + assertion de distinction.
var written = new List<(int dim, string path, string hash)>();
foreach (int dim in new[] { 2, 5, 30 })
{
    using var h = KnownFunctionLandscape.RenderHeatmap(
        new RosenbrockFitness(), dimension: dim, nbSamples: 50, rng: new Random(42 + dim),
        width: 120, height: 120);

    var path = "assets/landscape_multidim_rosenbrock_d" + dim + ".png";
    var bytes = h.ToPngGdi();
    File.WriteAllBytes(path, bytes);

    var hash = Convert.ToHexString(SHA256.HashData(bytes));
    written.Add((dim, path, hash));

    var (px, py) = h.ToPixel(0.0, 0.0);
    Console.WriteLine("Rosenbrock dim=" + dim.ToString().PadLeft(2) + " - pixel(0,0) = " + h.Bitmap.GetPixel(px, py) + " (PNG: " + path + ", sha256=" + hash.Substring(0, 12) + ").");
}
if (written.Select(x => x.hash).Distinct().Count() != written.Count)
{
    foreach (var w in written) Console.Error.WriteLine("  d" + w.dim + "  " + w.hash);
    throw new InvalidOperationException("Collision de rendu Rosenbrock : deux dimensions ont produit le meme PNG (hash identiques).");
}
Console.WriteLine("Rosenbrock d2/d5/d30 distincts : "
    + string.Join(", ", written.Select(w => "d" + w.dim + "=" + w.hash.Substring(0, 12))));
Rosenbrock dim= 2 - pixel(0,0) = Color [A=255, R=255, G=0, B=0] (PNG: assets/landscape_multidim_rosenbrock_d2.png, sha256=AE88ECD5F7D2).
Rosenbrock dim= 5 - pixel(0,0) = Color [A=255, R=255, G=7, B=0] (PNG: assets/landscape_multidim_rosenbrock_d5.png, sha256=B7BBEA88982D).
Rosenbrock dim=30 - pixel(0,0) = Color [A=255, R=234, G=255, B=0] (PNG: assets/landscape_multidim_rosenbrock_d30.png, sha256=764196A80A50).
Rosenbrock d2/d5/d30 distincts : d2=AE88ECD5F7D2, d5=B7BBEA88982D, d30=764196A80A50

Griewank en \(n = 2, 5, 30\) : produit-cosinus vs Ackley somme-cosinus

Différence structurelle avec Ackley (cf MGS-7b Ackley c.785) :

Fonction Formule cosinus Type Signature 2-D
Ackley \(-\exp(\frac{1}{n}\sum \cos(2\pi x_i))\) somme bassine large, anneaux concentriques
Griewank \(-\prod \cos(\frac{x_i}{\sqrt{i}})\) produit bandes ondulantes perpendiculaires

En 2-D, le produit \(\cos(x_0) \cdot \cos(x_1/\sqrt{2})\) génère des bandes verticales ondulantes (la fréquence décroît avec l’index \(i\), donc \(\cos(x_1/\sqrt{2})\) est 1.4× plus lent que \(\cos(x_0)\)). En 30-D, le produit de 30 cosinus à fréquences très diverses s’aplatit presque entièrement sous MAX — le canal vert devient quasi-uniforme (moy(G)=254,0, var(G)=69,8), teinté d’un rouge résiduel structuré (moy(R)=71,8) ; le bleu résiduel est faible (14,0).

INTRINSIC LIMIT documenté : Griewank en \(n \geq 10\) est essentiellement invisible via MAX-projection. C’est cohérent avec le fait que Griewank est conçu pour tester les métaheuristiques (qui peuvent descendre le long de la structure), pas les projections 2-D.

using System.IO;
using System.Security.Cryptography;
// Piege #12457 : un unique Random etatique partage entre les dimensions rend
// d30 quasi-confondu a d2. RNG independant par dimension + assertion de distinction.
var written = new List<(int dim, string path, string hash)>();
foreach (int dim in new[] { 2, 5, 30 })
{
    using var h = KnownFunctionLandscape.RenderHeatmap(
        new GriewankFitness(), dimension: dim, nbSamples: 50, rng: new Random(7 + dim),
        width: 120, height: 120);

    var path = "assets/landscape_multidim_griewank_d" + dim + ".png";
    var bytes = h.ToPngGdi();
    File.WriteAllBytes(path, bytes);

    var hash = Convert.ToHexString(SHA256.HashData(bytes));
    written.Add((dim, path, hash));

    var (px, py) = h.ToPixel(0.0, 0.0);
    Console.WriteLine("Griewank dim=" + dim.ToString().PadLeft(2) + " - pixel(0,0) = " + h.Bitmap.GetPixel(px, py) + " (PNG: " + path + ", sha256=" + hash.Substring(0, 12) + ").");
}
if (written.Select(x => x.hash).Distinct().Count() != written.Count)
{
    foreach (var w in written) Console.Error.WriteLine("  d" + w.dim + "  " + w.hash);
    throw new InvalidOperationException("Collision de rendu Griewank : deux dimensions ont produit le meme PNG (hash identiques).");
}
Console.WriteLine("Griewank d2/d5/d30 distincts : "
    + string.Join(", ", written.Select(w => "d" + w.dim + "=" + w.hash.Substring(0, 12))));
Griewank dim= 2 - pixel(0,0) = Color [A=255, R=255, G=4, B=0] (PNG: assets/landscape_multidim_griewank_d2.png, sha256=E63E5AB748AA).
Griewank dim= 5 - pixel(0,0) = Color [A=255, R=255, G=11, B=0] (PNG: assets/landscape_multidim_griewank_d5.png, sha256=08E8023BDB79).
Griewank dim=30 - pixel(0,0) = Color [A=255, R=42, G=255, B=0] (PNG: assets/landscape_multidim_griewank_d30.png, sha256=1A21D4092B12).
Griewank d2/d5/d30 distincts : d2=E63E5AB748AA, d5=08E8023BDB79, d30=1A21D4092B12
// Mesure de la structure par canal des six rendus ecrits ci-dessus.
// Les quantites du tableau « Tell visuel (mesure) » ci-dessous (variance et
// moyenne de R, G et B) sont PRODUITES ici au lieu d'etre recopiees dans la
// prose. Elles sont lues sur les PNG committes -- donc exactement sur les
// heatmaps des sections precedentes (graines 42 + dim pour Rosenbrock,
// 7 + dim pour Griewank), aucun re-rendu.
using System.Drawing;

var fichiers = new[] {
    ("Rosenbrock", "rosenbrock",  2), ("Rosenbrock", "rosenbrock",  5),
    ("Rosenbrock", "rosenbrock", 30),
    ("Griewank",   "griewank",    2), ("Griewank",   "griewank",    5),
    ("Griewank",   "griewank",   30),
};
var mesures = new List<(string fonction, int dim, double varR, double varG, double varB,
                       double moyR, double moyG, double moyB)>();
foreach (var (fonction, slug, dim) in fichiers)
{
    using var img = new Bitmap("assets/landscape_multidim_" + slug + "_d" + dim + ".png");
    double sR = 0, sG = 0, sB = 0, qR = 0, qG = 0, qB = 0;
    long n = 0;
    for (int ligne = 0; ligne < img.Height; ligne++)
    {
        for (int colonne = 0; colonne < img.Width; colonne++)
        {
            var c = img.GetPixel(colonne, ligne);
            sR += c.R; sG += c.G; sB += c.B;
            qR += (double)c.R * c.R; qG += (double)c.G * c.G; qB += (double)c.B * c.B;
            n++;
        }
    }
    double mR = sR / n, mG = sG / n, mB = sB / n;
    mesures.Add((fonction, dim, qR / n - mR * mR, qG / n - mG * mG, qB / n - mB * mB,
                 mR, mG, mB));
}

Console.WriteLine("Structure par canal des six rendus (variance et moyenne de R, G, B) :");
foreach (var m in mesures)
{
    Console.WriteLine(m.fonction.PadRight(12) + " d" + m.dim.ToString().PadLeft(2)
        + "  var(R)=" + m.varR.ToString("0.0").PadLeft(8)
        + " var(G)=" + m.varG.ToString("0.0").PadLeft(8)
        + " var(B)=" + m.varB.ToString("0.0").PadLeft(8)
        + "  | moy(R)=" + m.moyR.ToString("0.0").PadLeft(6)
        + " moy(G)=" + m.moyG.ToString("0.0").PadLeft(6)
        + " moy(B)=" + m.moyB.ToString("0.0").PadLeft(6));
}
Structure par canal des six rendus (variance et moyenne de R, G, B) :
Rosenbrock   d 2  var(R)=  2736,8 var(G)=  7607,8 var(B)=   250,4  | moy(R)= 239,2 moy(G)=  81,4 moy(B)=   1,9
Rosenbrock   d 5  var(R)=  2070,8 var(G)=  6982,0 var(B)=   151,8  | moy(R)= 242,5 moy(G)=  96,3 moy(B)=   1,2
Rosenbrock   d30  var(R)=  5162,4 var(G)=   841,8 var(B)=   119,3  | moy(R)= 177,9 moy(G)= 243,5 moy(B)=   1,4
Griewank     d 2  var(R)=  7711,3 var(G)=  6692,0 var(B)=   832,7  | moy(R)= 189,9 moy(G)= 190,7 moy(B)=   6,8
Griewank     d 5  var(R)=  6424,1 var(G)=  5591,2 var(B)=   321,7  | moy(R)= 199,2 moy(G)= 195,0 moy(B)=   3,3
Griewank     d30  var(R)=  5084,6 var(G)=    69,8 var(B)=  1038,1  | moy(R)=  71,8 moy(G)= 254,0 moy(B)=  14,0

Tell visuel (mesuré)

Confrontation de la section précédente aux images effectivement produites (assets/landscape_multidim_{rosenbrock,griewank}_d{2,5,30}.png), mesurées par variance/moyenne par canal (RGB). Les 36 valeurs du tableau sont recopiées de la sortie de la cellule de mesure ci-dessus, calculée sur les 14 400 pixels de chaque rendu, avec la variance de population (ddof=0, moyenne des carrés des écarts à la moyenne — la convention que reprend l’exercice 1 ; la cellule imprime ces mêmes valeurs avec la virgule décimale : 2736,8 y vaut 2736.8 ici) :

fonction d var(R) var(G) var(B) moy(R) moy(G) moy(B)
Rosenbrock 2 2736.8 7607.8 250.4 239.2 81.4 1.9
Rosenbrock 5 2070.8 6982.0 151.8 242.5 96.3 1.2
Rosenbrock 30 5162.4 841.8 119.3 177.9 243.5 1.4
Griewank 2 7711.3 6692.0 832.7 189.9 190.7 6.8
Griewank 5 6424.1 5591.2 321.7 199.2 195.0 3.3
Griewank 30 5084.6 69.8 1038.1 71.8 254.0 14.0

Lecture mesurée sur le rendu déterministe (corrige les trois affirmations de la section précédente) :

  1. « progressivement plus uniformes » — refuté sur Rosenbrock, atténué sur Griewank : var(R) MONTE sur Rosenbrock (2736,8→5162,4 = ×1,9 plus structurée en d30) et ne décroît que modérément sur Griewank (7711,3→5084,6 = ×1,5). La structure fine ne disparaît PAS sous MAX dans le rendu déterministe — le MAX sur 50 tirages par pixel laisse un relief inter-pixels ample.
  2. « Rosenbrock 30-D quasi-uniform-rouge » — la couleur est un champ orange-vert (moy(R)=177,9, moy(G)=243,5) où le bleu a disparu (moy(B)=1,4) ; et la quasi-uniformité est fausse (var(R)=5162,4, la plus élevée des trois dimensions).
  3. « gradient de rouge dominant » — vrai en d2/d5 sur Rosenbrock (moy(R) 239,2 / 242,5 devant moy(G) 81,4 / 96,3) ; Griewank d30 bascule côté vert (moy(G)=254,0, var(G)=69,8 : canal quasi-uniforme) avec un rouge résiduel (71,8).

Cause de l’écart avec la version d’origine : les images précédentes étaient générées avec un unique Random partagé entre les dimensions (d=2 ne consomme aucun tirage, d=5/d=30 consomment un état RNG de plus en plus avancé) — cf #12457. La projection N-D elle-même est correcte ; l’artefact était dans la pipeline de rendu, déclenchée par l’état RNG partagé. Le fix (RNG indépendant par dimension + assertion de distinction SHA-256) restaure des rendus fidèles. Les mesures ci-dessus proviennent du rendu déterministe par pixel (MetaGeneticSharp #49 : seed RNG dérivé par pixel, indépendant de l’ordonnancement Parallel.For) : les lignes d=2 sont inchangées (aucune coordonnée cachée), les lignes d=5/d=30 sont les premières reproductibles run-to-run — les lectures précédentes décrivaient un tirage non reproductible.

Exercices

Exercice 1 : quantifier la disparition de la vallée Rosenbrock

Mesurez la variance spatiale du canal rouge entre les heatmaps Rosenbrock en dimensions 2, 5 et 30. Si la vallée disparaît, cette variance devrait chuter nettement — mais le rendu déterministe ci-dessus suggère au contraire une hausse en dimension 30. Calculez les trois variances puis le ratio variance(d2) / variance(d30) pour confronter l’intuition à la mesure.

Indice : collectez la composante R des 14 400 pixels de chaque bitmap, puis utilisez la moyenne des carrés des écarts à la moyenne.

// EXERCICE 1 : variance du canal rouge selon la dimension.
// TODO etudiant : calculer la variance de R pour chaque heatmap.
var variancesRouges = new List<(int dimension, double variance)>();
foreach (int dim in new[] { 2, 5, 30 })
{
    using var heatmap = KnownFunctionLandscape.RenderHeatmap(
        new RosenbrockFitness(), dimension: dim, nbSamples: 50,
        rng: new Random(42 + dim), width: 120, height: 120);

    // Etape 1 : collecter heatmap.Bitmap.GetPixel(x, y).R pour tous les pixels.
    // Etape 2 : calculer moyenne puis moyenne des ecarts au carre.
    // Etape 3 : ajouter (dim, variance) a variancesRouges.
}

Console.WriteLine("Exercice 1 a completer : mesurer variance(R) en d2, d5 et d30.");
Exercice 1 a completer : mesurer variance(R) en d2, d5 et d30.

Exercice 2 : comparer les signatures fréquentielles de Griewank et Ackley

Comparez en dimension 2 la structure répétitive de Griewank à celle d’Ackley. À partir du canal rouge de chaque heatmap, construisez un profil horizontal moyen, puis comparez la fréquence dominante des deux profils. L’objectif est de vérifier quantitativement la différence entre produit de cosinus et somme de cosinus.

Indice : moyennez le canal rouge colonne par colonne avant d’appliquer une transformée discrète de Fourier ; ignorez la composante continue lors de la recherche du maximum spectral.

// EXERCICE 2 : profils spectraux Griewank et Ackley en dimension 2.
// TODO etudiant : extraire les profils horizontaux moyens puis leur frequence dominante.
var heatmapGriewank = KnownFunctionLandscape.RenderHeatmap(
    new GriewankFitness(), dimension: 2, nbSamples: 50,
    rng: new Random(7), width: 120, height: 120);
var heatmapAckley = KnownFunctionLandscape.RenderHeatmap(
    new AckleyFitness(), dimension: 2, nbSamples: 50,
    rng: new Random(99), width: 120, height: 120);

// Etape 1 : moyenner le canal R de chaque colonne pour chaque heatmap.
// Etape 2 : calculer la transformee discrete de Fourier des deux profils.
// Etape 3 : ignorer la composante continue et comparer les pics dominants.
Console.WriteLine("Exercice 2 a completer : comparer les frequences dominantes Griewank/Ackley.");
heatmapGriewank.Dispose();
heatmapAckley.Dispose();
Exercice 2 a completer : comparer les frequences dominantes Griewank/Ackley.

Exercice 3 : compter les minima locaux en 2-D

Estimez la multimodalité visible en comptant les minima locaux stricts dans les heatmaps Rosenbrock et Griewank en dimension 2. Un pixel intérieur est un minimum local si son canal rouge est strictement inférieur à ceux de ses quatre voisins directs. Comparez les deux comptes et affichez leur ratio.

Indice : parcourez seulement les pixels intérieurs (1..118) afin que chaque pixel possède quatre voisins ; traitez séparément un éventuel dénominateur nul.

// EXERCICE 3 : minima locaux stricts en dimension 2.
// TODO etudiant : compter les minima locaux de Rosenbrock et Griewank.
var heatmapRosenbrock2D = KnownFunctionLandscape.RenderHeatmap(
    new RosenbrockFitness(), dimension: 2, nbSamples: 50,
    rng: new Random(42), width: 120, height: 120);
var heatmapGriewank2D = KnownFunctionLandscape.RenderHeatmap(
    new GriewankFitness(), dimension: 2, nbSamples: 50,
    rng: new Random(42), width: 120, height: 120);

// Etape 1 : parcourir x et y de 1 a 118.
// Etape 2 : comparer R(x,y) aux quatre voisins directs.
// Etape 3 : afficher les deux comptes et leur ratio.
Console.WriteLine("Exercice 3 a completer : compter les minima locaux Rosenbrock/Griewank.");
heatmapRosenbrock2D.Dispose();
heatmapGriewank2D.Dispose();
Exercice 3 a completer : compter les minima locaux Rosenbrock/Griewank.

Liens

  • MGS-7b LandscapeMultidim — Ackley dim ∈ {2, 30} (c.785 PR #7993), Rastrigin/Schwefel/Sphere dim ∈ {2, 5, 10, 30} (c.732 PR #7583).
  • MGS-6 Benchmarks — les 10 fonctions canoniques et leur banc CEC d’origine.
  • MGS-8 LandscapeExplorer — exploration interactive GTK#.
  • Issue #7483 — port de la projection N-D (parent).
  • Issue #7997 — c.787 MGS-7c Rosenbrock+Griewank (sujet de ce notebook).
  • PR #7583 — port initial MGS-7b N-D.
  • PR #7993 — c.785 MGS-7b Ackley.
  • L785-L2 ★ — inversion chromatique chiffrable d2 → d30 = signature projection MAX.
Retour au sommet