|
| 1 | +--- |
| 2 | +title: "Synthèse des sessions de développement — optimiseurs PLNmodels" |
| 3 | +subtitle: "8-17 juin 2026 (branche `code-enhancement`) et 2-3 juillet 2026 (branche `optim-plnpca`)" |
| 4 | +date: 2026-07-03 |
| 5 | +format: |
| 6 | + html: |
| 7 | + toc: true |
| 8 | + toc-depth: 3 |
| 9 | + number-sections: true |
| 10 | +--- |
| 11 | + |
| 12 | +Ce document consolide les journaux de développement `DEVLOG_2026-06-08-17.md` et |
| 13 | +`DEVLOG_2026-07-02-03.md` (racine du dépôt) en une synthèse : l'état effectivement |
| 14 | +implémenté dans le package, les pistes explorées avec leur verdict, et un résumé |
| 15 | +bref des bugs corrigés. Le détail complet (chiffres, code, benchmarks) reste dans |
| 16 | +les DEVLOG originaux ; ce document sert de point d'entrée rapide. |
| 17 | + |
| 18 | +# Ce qui est effectivement implémenté dans le package aujourd'hui |
| 19 | + |
| 20 | +## Architecture commune (`covariance_pln.h`) |
| 21 | + |
| 22 | +Les cinq structures de covariance PLN (full, diagonal, spherical, fixed, **genpop**) |
| 23 | +partagent un unique moteur via CRTP statique (`CovTraitsBase<Derived>`) : |
| 24 | +gradient/objectif/pas de Newton joint (M, ψ) factorisés une seule fois, plus |
| 25 | +`diag_scale`/`add_diag` pour éviter les allocations p×p inutiles. Le CRTP statique a |
| 26 | +été préféré au polymorphisme virtuel : pas de vtable dans la boucle chaude, `has_em` |
| 27 | +exploité comme `constexpr bool` dans un `if constexpr`, et `State` de forme variable |
| 28 | +selon la structure (matrice dense, `rowvec`, ou deux `double`). ZIPLN réutilise cette |
| 29 | +même machinerie (`A_eff = (1-R) ⊙ A`, `w = ones(n)`) au lieu d'un second jeu de |
| 30 | +formules dupliqué. |
| 31 | + |
| 32 | +## Backends par modèle (état final) |
| 33 | + |
| 34 | +| Modèle | Défaut | Backends disponibles | Optimiseur `builtin` | |
| 35 | +|---|---|---|---| |
| 36 | +| PLN / PLNLDA | **nlopt** (`profiled=TRUE`) | nlopt, builtin, torch (exp.) | Newton joint (M,ψ), B profilé par enveloppe | |
| 37 | +| PLNPCA | **nlopt** | nlopt, builtin, torch (exp.) | Newton profilé à région de confiance (Steihaug-CG préconditionné) — remplace l'ancien spectral BB | |
| 38 | +| PLNnetwork | **builtin** (`maxit_ve=1`, inception builtin K=5) | builtin, nlopt | Newton VE-step + M-step glasso | |
| 39 | +| ZIPLN | **builtin** | builtin, nlopt | Newton joint (M,ψ,R), B profilé | |
| 40 | +| ZIPLNnetwork | **builtin** (depuis le 18/06) | builtin, nlopt | idem ZIPLN + glasso | |
| 41 | +| PLNmixture | builtin | builtin, nlopt, torch (exp.) | composants PLNfit standards | |
| 42 | + |
| 43 | +## Autres changements livrés |
| 44 | + |
| 45 | +- Normalisation uniforme des covariables (`normalize_covariates()`) dans tous les `optimize()`. |
| 46 | +- `future`/`future.apply` → `parallel::mclapply` (10 sites), pilotable via `options(mc.cores=N)`. |
| 47 | +- Init ZIPLN par LM + GLM binomial (`pscl` retiré des dépendances, ×60-240 plus rapide). |
| 48 | +- Init PLNPCA par LM par défaut ; EM tronqué (`init_method="EM"`) en option pour les grands rangs. |
| 49 | +- `PLNnetwork`/`ZIPLNnetwork` héritent correctement de `config_optim` pour leur modèle d'inception. |
| 50 | +- README.qmd (exécuté, sur `barents`) et vignette ZIPLN (sur `microcosm`) ajoutés. |
| 51 | +- 5ᵉ covariance `genpop` (héritabilité, $\Sigma = \sigma^2(\rho C + (1-\rho)I)$) câblée pour `PLN()` seul. |
| 52 | + |
| 53 | +## Session de juillet (branche `optim-plnpca`, en cours) |
| 54 | + |
| 55 | +Nouveau backend `builtin` pour PLNPCA : Newton profilé à région de confiance avec |
| 56 | +complément de Schur, remplaçant l'ancien optimiseur spectral (supprimé). `nlopt` |
| 57 | +reste le défaut. |
| 58 | + |
| 59 | +# Pistes explorées — conservées vs abandonnées |
| 60 | + |
| 61 | +| Piste | Statut | Pourquoi | |
| 62 | +|---|---|---| |
| 63 | +| Newton coordonnée (`homemade`) puis B profilé par enveloppe (`homemade_alt`) | **Conservé**, fusionné en un seul backend `builtin` | B profilé + Armijo à pente projetée (Q_step) élimine le cold-start et bat l'ancienne version partout | |
| 64 | +| `hybrid` (nlopt → Newton) | **Abandonné**, supprimé | Ne dépasse jamais `builtin` seul, systématiquement plus lent | |
| 65 | +| Hessienne M exacte (bloc p×p par obs.) / `block_newton_thresh` | **Abandonné**, supprimé | Coût O(np³) prohibitif, aucun gain de loglik vs l'approximation diagonale par blocs | |
| 66 | +| Pas Newton conjoint (M,ψ) avec terme croisé | **Conservé** | Capture le couplage M-S, remplace le point fixe séparé (plus lent) | |
| 67 | +| Warm-start Ω dans GLASSO (intra/inter-modèles) | **Abandonné**, reverté | Pire en qualité ET en temps (Σ change trop entre itérations / path de pénalités dans le mauvais sens) | |
| 68 | +| `maxit_ve` (E-step Newton partiel) pour PLNnetwork/ZIPLNnetwork | **Conservé** | Neutralise les oscillations de l'alternance GLASSO↔VE-step sur-convergée | |
| 69 | +| Inception tronquée (`inception_niter`, `init_method="EM"`) | **Conservé**, en option | Aide les grands rangs/modèles pénalisés (M "à mi-chemin") ; nuit aux petits rangs (sur-convergence) — sweet spot K=2–10 | |
| 70 | +| `approx_ZI` (formule Lambert W "exacte" pour R) | **Abandonné**, supprimé | La formule σ(·) est l'optimum exact de l'ELBO ; Lambert W optimise une autre fonctionnelle et donne un ELBO pire de 77-86 points | |
| 71 | +| L-BFGS bloc-alterné (EM) pour PLNPCA | **Abandonné** | 7-10× plus lent que le joint, gain de loglik nul (convergence EM extérieure linéaire) | |
| 72 | +| L-BFGS joint + Wolfe fort (PLNPCA, ancien "builtin") | **Conservé un temps puis remplacé** en juillet | Battait nlopt sur 6/9 cas, mais surclassé par le nouveau Newton région de confiance (juillet) | |
| 73 | +| SQUAREM (accélération EM) sur ZIPLN/PLNmixture | **Abandonné** (pas de défaut) | Coupe les cycles externes mais chaque cycle coûte plus cher ; net plus lent (25-40%) ; léger mieux d'ELBO seulement | |
| 74 | +| Newton région de confiance + Schur pour PLNPCA | **Conservé**, devient `builtin` | Bat nlopt et l'ancien builtin sur qualité et vitesse ; convergence lente à grand n comprise et acceptée (indéfini du Hessien réduit) | |
| 75 | +| Garde-fou CG "stop si résidu grossit" | **Abandonné** | Empire les résultats (les itérations errantes produisent quand même de bons pas) | |
| 76 | +| Warm-start entre rangs PLNPCA (`sequential`) | **Abandonné par défaut**, gardé en option | Net négatif pour Newton-TR (coût dans la rampe indéfinie, pas dans la distance à l'init) | |
| 77 | +| GLTR/Lanczos (solveur TR indéfini exact) | **Non retenu** | ROI incertain, ~150 lignes, pas déjà quasi-exacts | |
| 78 | + |
| 79 | +# Bugs corrigés (résumé) |
| 80 | + |
| 81 | +- `ifelse()` au lieu de `if/else` dans le dispatch backend de PLNLDAfit (diagonal/spherical) → crash torch. |
| 82 | +- `PLNfit_fixedcov` : VE-step manquant dans `setup_optimizer` → crash `predict(level=1)`. |
| 83 | +- PLNmixture : clé `maxit_out` au lieu de `maxit_em` → smoothing 25× trop lent. |
| 84 | +- `do.call` sensible à l'ordre des noms dans jackknife/bootstrap PLNfit. |
| 85 | +- M sans `colnames` après VE-step → perte des noms d'espèces en prédiction. |
| 86 | +- `latent_pos` de PLNmixturefit utilisait M_full au lieu de M_res → k-means biaisé. |
| 87 | +- `compute_PLN_starting_point` : NA non protégés, `singular.ok=FALSE` rendait un garde-fou inaccessible. |
| 88 | +- `extract_model` : détection de formule incomplète (`is.symbol` → `!inherits`). |
| 89 | +- Gradient faux dans `nlopt_optimize_vestep_spherical` (signe/direction M vs ω²). |
| 90 | +- `solve()` sur matrice 0×0 quand formule sans covariable (`~0`). |
| 91 | +- Initialisation M de PLNPCA : mauvais indexage SVD (`v[1:q,1:q]` au lieu des colonnes) → résidu ‖M·Cᵀ−M_PLN‖ divisé par ~100 après fix. |
| 92 | +- Bug XTOL nlopt prématuré sur covariables mal conditionnées (barents Depth~300) → régression majeure (+4118 ll après fix). |
| 93 | +- ZIPLNnetwork bloqué à `nlopt` par un `stopifnot` alors qu'architecturalement compatible avec builtin. |
| 94 | +- `browser()` oublié en debug dans ZIPLNfit. |
| 95 | +- Warning igraph (`frame.color` NA comme attribut au lieu d'argument `plot()`). |
| 96 | +- Signe de `dJ/dρ` dans la bissection de la covariance `genpop` (ρ convergeait toujours vers la borne basse). |
| 97 | +- (Session juillet) crash `solve()` et non-convergence à l'échelle pour le nouveau Newton-TR PLNPCA (tolérance absolue au lieu de relative) ; normalisation X incompatible avec la région de confiance. |
0 commit comments