1.**273,15 au lieu de 273,0** : ecoPrimers calcule `Tm(K) - 273.0`, `obithermo` utilise la valeur exacte 273,15 (Tm 0,15 °C plus bas ; le test tient compte du décalage). **Validé par l'utilisateur le 2026-11-03 : on garde 273,15.**
Le rôle « contexte » est nouveau (aujourd'hui : exemple, contre-exemple, ignorée). L'option « éviter les autres
clades » (20.3-2) transforme simplement leurs séquences de contexte en contre-exemples.
**Écart avec ecoPrimers à noter** : le Bs d'ecoPrimers ne juge l'unicité que parmi les exemples, même quand des
contre-exemples sont amplifiés. Proposition : **garder le Bs d'ecoPrimers inchangé** (c'est ce qui reproduit
les tables de référence) et ajouter un second indice calculé sur tout ce qui est amplifié (nom à choisir,
p. ex. `bs_all`), qui sert à la sélection multi-marqueurs ; il coïncide avec `bs` quand il n'y a ni
contre-exemple amplifié ni contexte.
### 21.3 Optimisation de Tm (proposition, paramètres de l'utilisateur)
- **Paramètres** : `Tm cible` et `écart de Tm maximal`. Proposition d'interprétation : la cible porte sur la
**moyenne des deux amorces** et l'écart borne leur différence, ce qui revient à imposer à chaque amorce
`cible ± écart/2`.
- **Où** : phase **après** la sélection des paires, sur chaque paire retenue : choisir les longueurs
`(L1, L2)` des deux amorces satisfaisant la cible et l'écart.
- **Ce qui rend la phase possible** : raccourcir une amorce **par son extrémité 5'** ne peut que conserver ou
réduire ses erreurs sur chaque site (c'est une sous-chaîne), donc la sensibilité est conservée. Allonger
par le 5' demande de **revérifier** les sites. Raccourcir fait en revanche perdre de la spécificité
(l'amorce raccourcie peut s'apparier ailleurs), d'où la nécessité de **réévaluer la paire** (sensibilité,
faux positifs, Bc, Bs, Tm) après chaque changement de longueur.
- **Réutilisation** : `obithermo` (Tm, Tm minimale), `MatchWords` et `FindPairs` sur une poignée de mots :
le coût est celui d'une évaluation par variante de longueur et par paire.
- **Intérêt pour le multiplex** : une Tm cible commune à toutes les paires d'un ensemble les rend compatibles
par construction.
- **Questions** : (a) la cible porte-t-elle sur la Tm de l'appariement parfait ou sur la Tm minimale sur les
sites (la pire), ou sur une valeur intermédiaire ? (b) bornes de longueur [Lmin, Lmax] ? Le mot actuel est
limité à 31 bases (codage 2 bits sur 64). (c) extension et raccourcissement seulement par le 5', en gardant
l'ancrage 3' ? (d) « pour n'importe quelle paire » : phase intégrée à la recherche, ou aussi outil
indépendant appliqué à des amorces fournies par l'utilisateur ? (e) une paire dont la Tm ne peut pas être
satisfaite dans les bornes : écartée ou signalée ?
### 21.4 Voie B : esquisse de spécification (proposition)
**But.** Une paire qui amplifie les cibles T (une espèce, ou quelques espèces très proches) et, autant que
possible, aucun de leurs voisins non cibles C. Facteur de conception : l'espace de recherche est élagué en
se concentrant sur les régions **non conservées** (celles où T diffère de C), l'inverse du mode A.
**Rôles.** T = exemples ; C = contre-exemples (voisins à ne pas amplifier) ; le reste, contexte ou ignoré.
**Constat.** Le pipeline actuel fait déjà fonctionner un cas voie B de façon naïve (`-r 8028 -i 8015`, *Salmo*
contre les autres Salmonidae : 7 exemples, 76 contre-exemples, 15 534 mots stricts), mais sans élagage, et le
critère « un quorum de faux positifs de 10 % » y est trop permissif pour une amorce spécifique.
**Principe d'une paire spécifique.** Une paire n'amplifie un voisin que si **ses deux amorces** s'y apparient.
Il suffit donc d'**une amorce spécifique** (loin de tous les sites de C) et d'une **amorce partenaire**
quelconque et conservée dans T, à distance d'amplicon permise. Les candidats se génèrent ainsi : mots de T
(quorum de T) dont aucun site à <= `e_exclusion` erreurs n'existe dans C (au-delà du quorum de faux
positifs) ; puis le partenaire dans la fenêtre d'amplicon de chaque occurrence dans T.
**Deux tolérances (proposition).**`-e` (sensibilité sur T) et une tolérance d'exclusion **`e_exclusion`** sur C,
éventuellement plus grande : un voisin est « amplifié » s'il s'apparie à `e_exclusion` erreurs ou moins. Cela
donne une marge de sécurité sans dégrader la sensibilité sur T.
**Score de marge (proposition).** Pour une amorce : nombre minimal d'erreurs d'un site de C ; pour la paire :
la meilleure des deux amorces (un voisin n'est amplifié que si les deux s'apparient), avec un poids
particulier pour les erreurs proches du 3'. Il compléterait Yule x Bs pour classer.
**Sortie.** Colonnes du mode A plus la marge des deux amorces.
**Échelle (à prévoir).** Pour T = un génome, le nombre de mots candidats est celui des positions du génome
(16 000 pour une mitochondrie, des millions pour une bactérie) : l'index de graines (`MatchWords`) indexe les
**mots** et balaie le texte de C ; pour des millions de mots il faudra les traiter par lots, chacun balayant C
une fois. À dimensionner selon l'usage visé.
**Questions pour finaliser.**
1.**Exclusion stricte ou marge** : une paire est-elle admise seulement si elle n'amplifie aucun voisin à
`e_exclusion` erreurs, ou classe-t-on par marge sans seuil dur ? Faut-il une contrainte particulière sur
les 3' derniers nucléotides des voisins (au moins une erreur dans les 5 dernières bases) ?
2.**Tailles typiques** de T et de C (une espèce avec combien de séquences ? voisins = un genre, une famille,
toute la base de 8 000 génomes mitochondriaux, des génomes entiers de bactéries ?).
3.**Type de séquences** : génomes organellaires entiers (comme le tutoriel), loci courts, génomes complets ?
4.**Plusieurs cibles** (quelques espèces proches) : amplifier le groupe sans les distinguer (détection de
groupe), ou les amplifier et les **résoudre** entre elles (Bs au sein de T, comme la spécialisation) ?
5.**Une amorce spécifique + une générale** est-il acceptable, ou les deux amorces doivent-elles être
spécifiques ?
6.**Sensibilité sur T** : quorum comme en mode A (0,9), ou toutes les séquences de T (intra-spécifique) ?
### 21.5 Travaux préalables communs (sans les engager)
Rôle « contexte » ; indice de résolution sur tout ce qui est amplifié ; ensembles d'espèces résolues par
paire ; corpus chargé une seule fois et sélection refaite en mémoire ; réévaluation d'une paire pour des
longueurs d'amorces variables ; marge d'une amorce (erreurs minimales sur C).
## 22. Réponses de l'utilisateur sur la résolution et la Tm (2026-11-03)
**Statut : spécification, aucun code.** La voie B attend les réponses de l'utilisateur (« encore un peu »).
### 22.1 Redéfinir Bs : oui (décision de principe, détails à confirmer)
Question de l'utilisateur : ecoPrimers calcule Bs sur les seules séquences amplifiées parce que ce sont les
seules chargées en mémoire ; ne vaudrait-il pas mieux **charger tout le monde, chercher les amorces
seulement dans une sélection, et tester sur tout le monde** ? Réponse : **oui**, et cela redéfinit Bs. Trois
populations distinctes :
| Population | Sert à |
|---|---|
| exemples (sélection de recherche) | générer les mots conservés ; sensibilité ; dénominateur de Bc et de Bs |
| contre-exemples | quorum de faux positifs |
| **tout le monde** (population d'évaluation) | juger l'unicité des amplicons : une espèce exemple est résolue si son amplicon n'est partagé avec aucun autre taxon amplifié, où qu'il soit dans la base |
Proposition de définition : `Bs = espèces exemples dont l'amplicon est unique parmi tous les taxons amplifiés de
la population d'évaluation / espèces exemples amplifiées`. Elle coïncide avec le Bs d'ecoPrimers quand la
population d'évaluation est la sélection (aucun contre-exemple ni contexte amplifié). **Piège à ne pas
oublier** : avec `-i 1` (validation de la section 17) le Bs d'ecoPrimers ignore les amplicons des
contre-exemples amplifiés ; la nouvelle définition changera donc ces valeurs. Pour garder les tests de
non-régression, proposition : conserver aussi le Bs d'ecoPrimers dans une colonne à part (p. ex.
`bs_examples`) et définir `bs` comme le nouvel indice ; à confirmer. Colonne informative à ajouter :
nombre de taxons hors exemples amplifiés.
**Mémoire (proposition)** : charger tout le monde n'est pas nécessaire pour un passage simple. Après la
recherche (sur la sélection, en mémoire), un **passage d'évaluation en flux** relit la base entière avec les
seules amorces des paires retenues (quelques centaines de mots : `MatchWords` en 0,04 s pour 65 Mb) et ne
conserve que, par paire, un hash d'amplicon et un taxon par séquence amplifiée, jamais les séquences. Coût :
une relecture du fichier (comme la double lecture de la taxonomie embarquée). Pour la sélection multi-marqueurs
(évaluations répétées par clade), une population d'évaluation **en mémoire sous forme compacte** (2 bits par
base, soit ~33 Mo pour les 131 Mb du tutoriel) serait préférable. À trancher à la spécification de la
sélection multi-marqueurs.
### 22.2 Longueur des amorces : 61 nucléotides (question de l'utilisateur)
L'utilisateur rappelle qu'agrep avait été réimplémenté en 64 bits pour des amorces jusqu'à 61 nucléotides
(`MAX_PAT_LEN` vaut 64 dans `obiapat/apat.h`). État **actuel** de obiprimers : **31 bases au maximum**, limite
inscrite dans `match.go:48`, `words.go:44`, `pairs.go:31`, dans `obikmer` (`encodekmer.go`,
`seqquorum.go:63` : k-mers sur 64 bits, 2 bits par base) et par des tampons fixes `[32]byte`
(`pairs_eval.go:208`). `obithermo` n'a pas de limite de longueur (tranches).
La stratégie de l'index de graines **n'est pas bloquée** : elle se généralise à 61 bases (et 64) avec une fenêtre
de **128 bits** (deux mots de 64 bits, décalage et popcount sur les deux) ; les moitiés (<= 31 bases) tiennent
dans un mot et le chemin d'index haché pour les grandes graines est déjà utilisé et testé (k = 25 et 31).
L'oracle de test existant (`matchNaive`) fixe la justesse. Le compteur de mots stricts (k-mers sur 64 bits,
type partagé d'`obikmer`) resterait limité à 31 : **proposition** : chercher les mots conservés avec un k <= 31
(le « coeur » conservé), puis obtenir les amorces plus longues par **extension** pendant la phase de Tm
(22.3), vérifiée par l'appariement généralisé.
### 22.3 Optimisation de Tm : réponses aux questions de 21.3
(a) **Cible sur l'apparié non parfait** (la Tm de l'amorce sur les sites réels, avec leurs erreurs), pas sur
l'appariement parfait. *Question restante* : quelle statistique des Tm de sites ? Le minimum (`tm_min` d'ecoPrimers)
est dominé par des valeurs aberrantes : sur les tables de référence on lit des minimums de 12 à 45 °C pour des
amorces dont la Tm parfaite est de 52 à 62 °C ; une cible sur le minimum imposerait des longueurs absurdes.
Proposition : cible sur la **moyenne ou la médiane** des Tm de sites (éventuellement pondérées par taxon), le
minimum restant rapporté ; ou un quantile bas réglable. À choisir.
(b) bornes de longueur : traitées en 22.2 (jusqu'à 61 bases possible avec la généralisation).
(c) **Extension et raccourcissement du côté le mieux conservé** (et non seulement par le 5', contrairement à ma
proposition). Cela se calcule avec un profil de conservation par position (fraction des sites cibles qui
portent la même base, comme le PSSM du tutoriel) autour de chaque amorce, tiré des occurrences déjà
trouvées. Attention : la contrainte `-3` s'applique à l'extrémité 3' *de l'amorce*, quelle que soit sa
position sur la séquence ; étendre ou raccourcir du côté 3' déplace donc cette extrémité et modifie la
longueur d'amplicon.
(d) **Intégrée à la recherche, en phase de post-traitement** de la même exécution de obiprimers (pas d'outil
indépendant pour l'instant).
(e) Une paire dont la Tm n'est pas atteignable dans les bornes est **écartée**.
### 22.4 En attente
Réponses de l'utilisateur sur la voie B (questions de 21.4) ; choix de la statistique de Tm (22.3-a) ; nom et
sort de l'ancien Bs (22.1) ; en-têtes éventuels à prévoir pour les colonnes de population d'évaluation.
## 23. Décisions : un seul Bs, tout en mémoire (2026-11-03)
**Statut : spécification, aucun code.** Cette section **remplace** la proposition de 22.1 (colonne `bs_examples`,
passage d'évaluation en flux).
### 23.1 Décisions de l'utilisateur
1.**Un seul indice Bs, calculé d'une seule façon.** Pas de colonne `bs_examples`, pas de variante : « on décide
un indice, il se calcule d'une certaine façon, point barre ». Le Bs d'ecoPrimers disparaît.
2.**Tout charger en mémoire.** Ne pas tout charger interdirait de lire la base de référence sur l'entrée
standard, que les obitools permettent ; la base est lue par le mécanisme de lecture standard
(comme `obiconvert`), sans format dédié. Le passage d'évaluation en flux de 22.1 est abandonné.
3.**Définition de Bs** : le nombre de taxons **bien identifiés parmi les cibles**, en considérant **tous les
barcodes amplifiés, y compris ceux hors des cibles et ceux des contre-exemples**. Une espèce cible est
mal identifiée si son barcode, unique parmi les cibles, est partagé avec une espèce non cible ou un
contre-exemple.
### 23.2 Définition formelle retenue (traduction de 23.1-3)
Pour une paire, soit A l'ensemble des séquences qu'elle amplifie, **de n'importe quel rôle** (cibles,
contre-exemples, autres). Pour un amplicon a, T(a) est l'ensemble des taxons (au rang choisi) des séquences de A
qui le portent. Un taxon cible t est **bien identifié** s'il existe un amplicon a produit par t avec T(a) = {t}.
### 23.3 Conséquences
- **Fin de la notion de séquence « ignorée »** : les séquences qui ne sont ni cibles ni contre-exemples ne sont
plus écartées à la lecture (comportement actuel, hérité d'ecoPrimers) ; elles sont **non cibles** : elles ne
comptent ni dans les quorums de sensibilité et de faux positifs, mais leurs amplicons comptent dans Bs.
Pour exclure des séquences de l'analyse, on filtre l'entrée en amont (`obigrep`), à la manière des obitools.
Le rôle « contexte » de 21.2 devient donc simplement « non cible ».
- **Les valeurs changent, y compris pour le tutoriel** : une paire conservée chez tous les vertébrés amplifie
aussi des non-Cyprinidae ; son Bs baissera par rapport aux tables d'ecoPrimers, même sans `-i`. Les tests de
non-régression de la section 17 et de la section 18 ne peuvent plus comparer Bs/identifiés avec ecoPrimers sur
la base entière. **Proposition, sans option ni colonne supplémentaire** : au niveau de la bibliothèque, un corpus
construit avec les seules cibles et contre-exemples (c'est ce que fait `LoadCorpus` aujourd'hui) redonne
exactement la définition d'ecoPrimers, car il n'y a alors aucune séquence hors sélection à amplifier ; les tests de
non-régression continuent d'utiliser ce corpus, la CLI charge toujours tout.
- **Coût mémoire** : tout le fichier est conservé (131 Mb de bases pour 194 Mo de tas dans le tutoriel, contre
5 Mb pour Cyprinidae aujourd'hui). Une représentation compacte (2 bits par base) reste possible plus tard ;
non décidée.
- **Coût de calcul** : l'appariement approché des mots et l'énumération des amplicons passent de la sélection à
tout le corpus (l'exécution `-r 7953 -i 1` du tutoriel, qui charge déjà tout, prend 1,9 s) ; les quorums ne
comptent toujours que cibles et contre-exemples.
### 23.4 Points à confirmer (propositions, non validées)
1.**Dénominateur de Bs** : taxons cibles **amplifiés** (comme le code d'ecoPrimers : 2 650 identifiés sur 3 805
amplifiés = 0,696) ou **tous** les taxons cibles ? Avec le premier, Bc (couverture) et Bs (discrimination)
restent indépendants et `Bc x Bs` est la part des cibles résolues par la paire, ce qui est le gain mesuré par
la sélection multi-marqueurs. Avec le second, Bs <= Bc et ce produit disparaît. **Je recommande le
premier.** L'article (« nombre de taxons identifiés sur |E| ») et le code divergent déjà.
2.**Taxon à plusieurs amplicons** : bien identifié dès qu'**un** de ses amplicons est unique (règle d'ecoPrimers),
ou seulement si **tous** le sont ? Je propose de garder la règle d'ecoPrimers.
3.**Séquence non cible sans taxon au rang choisi** : la traiter comme un taxon anonyme distinct (prudent :
elle empêche l'identification d'une cible qui partage son amplicon) ou l'ignorer ? Je propose le premier.
## 24. Règle d'identification de Bs, et l'indice BD (2026-11-03)
**Statut : spécification, aucun code.** Complète et corrige la section 23.
### 24.1 Décisions de l'utilisateur
1.**Dénominateur de Bs : les taxons cibles amplifiés** (comme ecoPrimers : 2 650 / 3 805 = 0,696).
Bc (couverture) et Bs (discrimination) restent indépendants ; `Bc x Bs` est la part des cibles résolues.
2. **Règle d'identification : une espèce est bien identifiée si TOUS ses barcodes ne sont associés qu'à
elle.** Dès qu'un barcode est partagé entre deux espèces, **les deux** sont mal identifiées. Cette règle
remplace celle de 23.4-2 (que j'avais proposé de garder).
3.**Nouvel indice BD (barcode discrimination)** proposé par l'utilisateur : la part des **barcodes** qui
mènent sans ambiguïté à une espèce cible. Exemple de l'utilisateur : A porte les barcodes A1 et A2, B porte
A2 et B1. Ni A ni B ne sont bien identifiées (elles partagent A2), mais **A1 et B1 sont discriminants**, A2
ne l'est pas. Ici Bs = 0/2 et BD = 2/3. (Avec la règle d'ecoPrimers on aurait Bs = 2/2.)
### 24.2 ecoPrimers applique bien l'autre règle (vérifié)
Lecture de `taxstats.c` : pour chaque amplicon distinct (parmi les exemples), on dresse l'ensemble de ses
taxons ; si cet ensemble n'a qu'**un** taxon (`taxoncount == 1`), ce taxon est marqué bien identifié. Un
taxon est donc compté **dès qu'un** de ses amplicons lui est propre. Confirmations : (i) mon implémentation de
cette règle reproduit toutes les colonnes `identifiés` et Bs de plus de vingt tables d'ecoPrimers (sections
12, 15, 17, 18) ; (ii) recalcul indépendant avec `obipcr` + Python sur la paire n° 1 de `Cyprinidae.ecoprimers`
(320 amplicons chez `obipcr`, 318 chez ecoPrimers qui impose `-3 2`) : règle « au moins un barcode unique »
239/312 = 0,766 contre 237/310 = 0,765 pour ecoPrimers ; règle « tous uniques » 238/312 = 0,763 ; **BD =
240/265 = 0,906** (265 barcodes distincts). **Portée de (ii)** : sur cette paire les deux règles ne diffèrent
que d'**une** espèce sur 312, car les données du tutoriel ont un génome par espèce (4 espèces seulement
portent plusieurs barcodes) : ce recalcul ne tranche pas entre les règles à lui seul ; la preuve est le code
et les tables reproduites.
### 24.3 Conséquences
- **Les différences entre règles seront faibles sur le tutoriel** (un génome par espèce) et **plus fortes**
sur des bases à plusieurs séquences par espèce (variation intra-spécifique), typiquement des bases de loci courts.
- **Non-régression** : la règle changeant, l'égalité des colonnes `identifiés` et Bs avec ecoPrimers n'est plus
atteignable, même avec un corpus restreint aux cibles et contre-exemples (annule la proposition de 23.3 sur ce
point). Toutes les autres colonnes (séquences, taxons, Bc, Yule, longueurs, GC, Tm, drapeaux good) restent
comparables. Pour Bs, BD et `identifiés` : tests sur cas synthétiques (dont l'exemple A1/A2/B1 ci-dessus) et
**vérification indépendante** par `obipcr` + script, comme en 24.2, sur des paires choisies.
- **Seuil `-T` (spécificité minimale, 0,6 par défaut)** : calibré sur l'ancienne règle, plus indulgente. Le
défaut sera peut-être à revoir ; à décider avec la spécification complète.
- **Implémentation (plus tard)** : la phase 2 de `FindPairs` doit enregistrer le hash d'amplicon de **toutes** les
séquences amplifiées (cibles, contre-exemples, non-cibles) et non plus des seuls exemples ; un taxon cible est
mal identifié si l'un de ses amplicons est porté par un autre taxon.
### 24.4 Questions restantes
1.**BD** : l'inclure dans la sortie, et dans le classement ? Dénominateur proposé : les barcodes distincts
portés par **au moins une cible** (un barcode propre à une non-cible ne « mène » pas à une espèce cible) ;
comptage par barcode distinct, sans pondération par le nombre de séquences.
2.**Non-cible sans taxon au rang choisi** (23.4-3, proposé, non confirmé) : taxon anonyme distinct, donc