[ADD] engine: indicators measured by full recomputation
Full recomputation is the measure every displayed figure comes from
(§ 5.10). It keeps the three collision units apart — cumulative
occurrences, distinct pairs, their excess — splits table returns and
repeated meetings into those the engine chose and those the reservations
impose, and gives null, never zero, for an empty population.
Checked: the small demonstration's perfect plan gives 8 met, A = 2,
r = 6, d = 0.25 for all twelve; spread and concentrated plans give
excess 0 and 4.
--- FR ---
[ADD] moteur : indicateurs mesurés par recalcul complet
Le recalcul complet est la mesure dont sort tout chiffre affiché
(§ 5.10). Il tient séparées les trois unités de collision — occurrences
cumulées, paires distinctes, leur excédent —, partage les retours à une
table et les rencontres répétées entre ceux que le moteur a choisis et
ceux qu'imposent les réservations, et rend null, jamais zéro, pour une
population vide.
Vérifié : le plan parfait de la petite démonstration donne 8 rencontres,
A = 2, r = 6, d = 0,25 pour les douze ; plans réparti et concentré
donnent un excédent de 0 et de 4.
Assisted-by: Claude Opus 5.5
2026-10-05 17:27:34 -04:00
|
|
|
|
// © 2026 TechnoLibre (http://www.technolibre.ca)
|
|
|
|
|
|
// License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
|
|
|
|
|
|
|
|
|
|
|
|
// Indicateurs d'un plan (§ 5.4), par recalcul complet : la mesure qui fait
|
|
|
|
|
|
// foi, dont sortent les chiffres affichés et ceux du classement (§ 5.10). Le
|
|
|
|
|
|
// plan se mesure entier, les N participants et les R tours ; les
|
|
|
|
|
|
// réservations ne retirent rien de la mesure, elles séparent seulement, dans
|
|
|
|
|
|
// les retours et les rencontres répétées, ce qu'elles imposent de ce que le
|
|
|
|
|
|
// moteur choisit. Tout tableau par personne suit l'ordre de instance.ids.
|
|
|
|
|
|
//
|
|
|
|
|
|
// Une rencontre est une paire de personnes assises à la même table au même
|
|
|
|
|
|
// tour : la réserve n'est pas une table, une table vide ou à un seul occupant
|
|
|
|
|
|
// ne forme aucune paire, et personne ne se rencontre soi-même. Deux personnes
|
|
|
|
|
|
// sans appartenance ne sont pas collègues. Un ensemble vide rend null, jamais
|
|
|
|
|
|
// 0 : le taux de diversité de qui ne rencontre aucun affilié, le minimum et la
|
|
|
|
|
|
// moyenne d'une population sans membre.
|
[IMP] engine: single owners, regeneration, property grid
The search recomputed the collision excess and the gaps that the measure
already gives — two arithmetics for one quantity. It now reads them from
the measure, and the redundancy total has one owner. Contract values, the
indexed-plan guard and the population split are defined once. regenerer
rebuilds a proposition from its derived seed, stop count and history
length, which the spec now lists (§ 8.9). A property grid runs seeded
random rooms through the whole chain.
Checked: 435 node and 20 long tests; redefining the excess or the gaps in
the measure now fails the search tests too.
--- FR ---
[IMP] moteur : propriétaires uniques, régénération, grille de propriétés
La recherche recalculait l'excédent de collisions et les écarts que la
mesure donne déjà — deux arithmétiques pour une grandeur. Elle les lit
désormais dans la mesure, et le total de redondance a un seul
propriétaire. Valeurs du contrat, garde du plan indexé et partition des
populations sont définies une fois. regenerer reconstruit une proposition
depuis sa graine dérivée, son arrêt et la longueur de son historique,
que le spec énumère désormais (§ 8.9). Une grille de propriétés fait
traverser toute la chaîne à des salles tirées d'une graine.
Vérifié : 435 épreuves node et 20 longues ; redéfinir l'excédent ou les
écarts dans la mesure fait désormais tomber aussi la recherche.
Assisted-by: Claude Opus 5.5
2026-10-06 04:23:02 -04:00
|
|
|
|
import {
|
|
|
|
|
|
RESERVE,
|
|
|
|
|
|
SANS_GROUPE,
|
|
|
|
|
|
exigerPlanIndexe,
|
|
|
|
|
|
replierParPopulation,
|
|
|
|
|
|
} from './configuration.js';
|
[ADD] engine: indicators measured by full recomputation
Full recomputation is the measure every displayed figure comes from
(§ 5.10). It keeps the three collision units apart — cumulative
occurrences, distinct pairs, their excess — splits table returns and
repeated meetings into those the engine chose and those the reservations
impose, and gives null, never zero, for an empty population.
Checked: the small demonstration's perfect plan gives 8 met, A = 2,
r = 6, d = 0.25 for all twelve; spread and concentrated plans give
excess 0 and 4.
--- FR ---
[ADD] moteur : indicateurs mesurés par recalcul complet
Le recalcul complet est la mesure dont sort tout chiffre affiché
(§ 5.10). Il tient séparées les trois unités de collision — occurrences
cumulées, paires distinctes, leur excédent —, partage les retours à une
table et les rencontres répétées entre ceux que le moteur a choisis et
ceux qu'imposent les réservations, et rend null, jamais zéro, pour une
population vide.
Vérifié : le plan parfait de la petite démonstration donne 8 rencontres,
A = 2, r = 6, d = 0,25 pour les douze ; plans réparti et concentré
donnent un excédent de 0 et de 4.
Assisted-by: Claude Opus 5.5
2026-10-05 17:27:34 -04:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @typedef {Object} Agregat
|
|
|
|
|
|
* @property {number|null} min null pour une population vide
|
|
|
|
|
|
* @property {number|null} moyenne null pour une population vide
|
|
|
|
|
|
* @property {number} effectif
|
|
|
|
|
|
*
|
|
|
|
|
|
* @typedef {Object} TroisAgregats
|
|
|
|
|
|
* @property {Agregat} tous
|
|
|
|
|
|
* @property {Agregat} mobiles mobiles et partiellement fixés (§ 5.4)
|
|
|
|
|
|
* @property {Agregat} ancres
|
|
|
|
|
|
*
|
|
|
|
|
|
* @typedef {Object} Mesures
|
|
|
|
|
|
* @property {number[]} rencontres |met(p)|, ordre canonique
|
|
|
|
|
|
* @property {number[]} affilies |F(p)|
|
|
|
|
|
|
* @property {number[]} appartenancesVues A(p) — appartenances des affiliés
|
|
|
|
|
|
* rencontrés, la sienne comprise quand
|
|
|
|
|
|
* un collègue est rencontré
|
|
|
|
|
|
* @property {number[]} redondance r(p) = |F(p)| − A(p)
|
|
|
|
|
|
* @property {(number|null)[]} diversite d(p) = A(p) / |F(p)|, null si |F(p)| = 0
|
|
|
|
|
|
* @property {number[]} toursAssis
|
|
|
|
|
|
* @property {number[]} retoursChoisis par personne
|
|
|
|
|
|
* @property {number[]} retoursImposes par personne
|
|
|
|
|
|
* @property {TroisAgregats} aggRencontres
|
|
|
|
|
|
* @property {TroisAgregats} aggRedondance
|
[IMP] engine: single owners, regeneration, property grid
The search recomputed the collision excess and the gaps that the measure
already gives — two arithmetics for one quantity. It now reads them from
the measure, and the redundancy total has one owner. Contract values, the
indexed-plan guard and the population split are defined once. regenerer
rebuilds a proposition from its derived seed, stop count and history
length, which the spec now lists (§ 8.9). A property grid runs seeded
random rooms through the whole chain.
Checked: 435 node and 20 long tests; redefining the excess or the gaps in
the measure now fails the search tests too.
--- FR ---
[IMP] moteur : propriétaires uniques, régénération, grille de propriétés
La recherche recalculait l'excédent de collisions et les écarts que la
mesure donne déjà — deux arithmétiques pour une grandeur. Elle les lit
désormais dans la mesure, et le total de redondance a un seul
propriétaire. Valeurs du contrat, garde du plan indexé et partition des
populations sont définies une fois. regenerer reconstruit une proposition
depuis sa graine dérivée, son arrêt et la longueur de son historique,
que le spec énumère désormais (§ 8.9). Une grille de propriétés fait
traverser toute la chaîne à des salles tirées d'une graine.
Vérifié : 435 épreuves node et 20 longues ; redéfinir l'excédent ou les
écarts dans la mesure fait désormais tomber aussi la recherche.
Assisted-by: Claude Opus 5.5
2026-10-06 04:23:02 -04:00
|
|
|
|
* @property {number} totalRedondance Σ_p r(p), le seul total de la
|
|
|
|
|
|
* redondance : la recherche et le
|
|
|
|
|
|
* classement le lisent
|
[ADD] engine: indicators measured by full recomputation
Full recomputation is the measure every displayed figure comes from
(§ 5.10). It keeps the three collision units apart — cumulative
occurrences, distinct pairs, their excess — splits table returns and
repeated meetings into those the engine chose and those the reservations
impose, and gives null, never zero, for an empty population.
Checked: the small demonstration's perfect plan gives 8 met, A = 2,
r = 6, d = 0.25 for all twelve; spread and concentrated plans give
excess 0 and 4.
--- FR ---
[ADD] moteur : indicateurs mesurés par recalcul complet
Le recalcul complet est la mesure dont sort tout chiffre affiché
(§ 5.10). Il tient séparées les trois unités de collision — occurrences
cumulées, paires distinctes, leur excédent —, partage les retours à une
table et les rencontres répétées entre ceux que le moteur a choisis et
ceux qu'imposent les réservations, et rend null, jamais zéro, pour une
population vide.
Vérifié : le plan parfait de la petite démonstration donne 8 rencontres,
A = 2, r = 6, d = 0,25 pour les douze ; plans réparti et concentré
donnent un excédent de 0 et de 4.
Assisted-by: Claude Opus 5.5
2026-10-05 17:27:34 -04:00
|
|
|
|
* @property {number} collisionsCumulees Σ paires de même groupe × tours ensemble
|
|
|
|
|
|
* @property {number} pairesDistinctes paires de même groupe réunies ≥ 1 fois
|
|
|
|
|
|
* @property {number} excedentCollisions cumulées − distinctes
|
|
|
|
|
|
* @property {{choisies: number, imposees: number}} rencontresRepetees
|
|
|
|
|
|
* paires réunies ≥ 2 fois ; « imposée » quand chaque rencontre de la
|
|
|
|
|
|
* paire a lieu à une table où les deux sont réservés ce tour-là
|
|
|
|
|
|
* @property {number} maxRencontresPaire sur toutes les paires ; 0 si aucune
|
|
|
|
|
|
* @property {number} totalRetoursChoisis
|
|
|
|
|
|
* @property {number} totalRetoursImposes
|
|
|
|
|
|
* @property {Array<{groupe: string, effectif: number, collisionsCumulees: number,
|
|
|
|
|
|
* pairesDistinctes: number, excedent: number}>} parGroupe
|
|
|
|
|
|
* ordre de instance.groupes
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
// Plus grand compte que tient un Uint16Array.
|
|
|
|
|
|
const UINT16_MAX = 0xffff;
|
|
|
|
|
|
|
|
|
|
|
|
// Rang de la paire (a, b), a < b, dans le triangle supérieur d'une matrice
|
|
|
|
|
|
// N × N rangé ligne par ligne : la ligne a s'ouvre après les
|
|
|
|
|
|
// (N − 1) + (N − 2) + … + (N − a) paires des lignes qui la précèdent.
|
|
|
|
|
|
const rangPaire = (N, a, b) => (a * (2 * N - a - 1)) / 2 + (b - a - 1);
|
|
|
|
|
|
|
|
|
|
|
|
// Rencontres de chaque paire, rangées par rangPaire, en parcourant chaque
|
|
|
|
|
|
// table de chaque tour. choisie vaut 1 pour une paire dont une rencontre au
|
|
|
|
|
|
// moins a lieu hors d'une table où les deux sont réservés ce tour-là. Une
|
|
|
|
|
|
// paire se réunit au plus une fois par tour : R borne chaque compte, qu'un
|
|
|
|
|
|
// Uint16Array tient tant que R ≤ 65 535.
|
|
|
|
|
|
function compterRencontres({ N, T, R, fixe }, tableDe) {
|
|
|
|
|
|
const paires = (N * (N - 1)) / 2;
|
|
|
|
|
|
const compte = R <= UINT16_MAX ? new Uint16Array(paires) : new Uint32Array(paires);
|
|
|
|
|
|
const choisie = new Uint8Array(paires);
|
|
|
|
|
|
for (let r = 0; r < R; r += 1) {
|
|
|
|
|
|
// Occupants de chaque table, par index croissants : a < b pour toute
|
|
|
|
|
|
// paire (liste[i], liste[j]) avec i < j. La boucle intérieure part du
|
|
|
|
|
|
// voisin suivant : une liste vide ou d'un seul occupant ne forme aucune
|
|
|
|
|
|
// paire, et nul n'est apparié à lui-même.
|
|
|
|
|
|
const assis = Array.from({ length: T }, () => []);
|
|
|
|
|
|
for (let p = 0; p < N; p += 1) {
|
|
|
|
|
|
const t = tableDe[p * R + r];
|
|
|
|
|
|
if (t !== RESERVE) assis[t].push(p);
|
|
|
|
|
|
}
|
|
|
|
|
|
for (let t = 0; t < T; t += 1) {
|
|
|
|
|
|
const liste = assis[t];
|
|
|
|
|
|
for (let i = 0; i < liste.length; i += 1) {
|
|
|
|
|
|
const a = liste[i];
|
|
|
|
|
|
const aReserve = fixe[a * R + r] === t;
|
|
|
|
|
|
for (let j = i + 1; j < liste.length; j += 1) {
|
|
|
|
|
|
const b = liste[j];
|
|
|
|
|
|
const k = rangPaire(N, a, b);
|
|
|
|
|
|
compte[k] += 1;
|
|
|
|
|
|
if (!aReserve || fixe[b * R + r] !== t) choisie[k] = 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return { compte, choisie };
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Lecture du triangle des paires, dans l'ordre de rangPaire. Par personne :
|
|
|
|
|
|
// |met(p)|, |F(p)| et A(p), vu[p * G + g] notant que p a déjà croisé un
|
|
|
|
|
|
// affilié du groupe g. Par groupe : une paire de collègues réunie n fois
|
|
|
|
|
|
// porte n collisions cumulées et une paire distincte. Sur toutes les paires :
|
|
|
|
|
|
// les rencontres répétées, choisies ou imposées, et le plus grand compte.
|
|
|
|
|
|
function lirePaires({ N, groupe, groupes }, { compte, choisie }) {
|
|
|
|
|
|
const G = groupes.length;
|
|
|
|
|
|
const rencontres = new Int32Array(N);
|
|
|
|
|
|
const affilies = new Int32Array(N);
|
|
|
|
|
|
const vues = new Int32Array(N);
|
|
|
|
|
|
const vu = new Uint8Array(N * G);
|
|
|
|
|
|
const collisions = new Array(G).fill(0);
|
|
|
|
|
|
const distinctes = new Array(G).fill(0);
|
|
|
|
|
|
let choisies = 0;
|
|
|
|
|
|
let imposees = 0;
|
|
|
|
|
|
let maxRencontresPaire = 0;
|
|
|
|
|
|
|
|
|
|
|
|
// p rencontre q : q compte dans met(p) ; un affilié compte aussi dans F(p),
|
|
|
|
|
|
// et son groupe compte dans A(p) au premier membre de ce groupe que p
|
|
|
|
|
|
// rencontre.
|
|
|
|
|
|
const rencontrer = (p, q) => {
|
|
|
|
|
|
rencontres[p] += 1;
|
|
|
|
|
|
const g = groupe[q];
|
|
|
|
|
|
if (g === SANS_GROUPE) return;
|
|
|
|
|
|
affilies[p] += 1;
|
|
|
|
|
|
if (vu[p * G + g] === 0) {
|
|
|
|
|
|
vu[p * G + g] = 1;
|
|
|
|
|
|
vues[p] += 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
let k = 0;
|
|
|
|
|
|
for (let a = 0; a < N; a += 1) {
|
|
|
|
|
|
for (let b = a + 1; b < N; b += 1, k += 1) {
|
|
|
|
|
|
const n = compte[k];
|
|
|
|
|
|
if (n === 0) continue;
|
|
|
|
|
|
rencontrer(a, b);
|
|
|
|
|
|
rencontrer(b, a);
|
|
|
|
|
|
if (n > maxRencontresPaire) maxRencontresPaire = n;
|
|
|
|
|
|
if (n >= 2) {
|
|
|
|
|
|
if (choisie[k] === 1) choisies += 1;
|
|
|
|
|
|
else imposees += 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
const g = groupe[a];
|
|
|
|
|
|
if (g !== SANS_GROUPE && g === groupe[b]) {
|
|
|
|
|
|
collisions[g] += n;
|
|
|
|
|
|
distinctes[g] += 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return {
|
|
|
|
|
|
rencontres,
|
|
|
|
|
|
affilies,
|
|
|
|
|
|
vues,
|
|
|
|
|
|
collisions,
|
|
|
|
|
|
distinctes,
|
|
|
|
|
|
rencontresRepetees: { choisies, imposees },
|
|
|
|
|
|
maxRencontresPaire,
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Tours assis et retours de chaque personne (§ 5.4). Pour une table visitée
|
|
|
|
|
|
// m fois, dont f à un tour où la personne y est réservée : max(0, f − 1)
|
|
|
|
|
|
// retours imposés et (m − 1) − imposés retours choisis. visites et reservees
|
|
|
|
|
|
// comptent par table les tours de la personne en cours ; le second parcours
|
|
|
|
|
|
// de ses tours solde chaque table à sa première occurrence et remet ses
|
|
|
|
|
|
// compteurs à zéro, si bien que la personne suivante les trouve nuls.
|
|
|
|
|
|
function compterRetours({ N, T, R, fixe }, tableDe) {
|
|
|
|
|
|
const toursAssis = [];
|
|
|
|
|
|
const retoursChoisis = [];
|
|
|
|
|
|
const retoursImposes = [];
|
|
|
|
|
|
const visites = new Int32Array(T);
|
|
|
|
|
|
const reservees = new Int32Array(T);
|
|
|
|
|
|
for (let p = 0; p < N; p += 1) {
|
|
|
|
|
|
let assis = 0;
|
|
|
|
|
|
for (let r = 0; r < R; r += 1) {
|
|
|
|
|
|
const t = tableDe[p * R + r];
|
|
|
|
|
|
if (t === RESERVE) continue;
|
|
|
|
|
|
assis += 1;
|
|
|
|
|
|
visites[t] += 1;
|
|
|
|
|
|
if (fixe[p * R + r] === t) reservees[t] += 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
let choisis = 0;
|
|
|
|
|
|
let imposes = 0;
|
|
|
|
|
|
for (let r = 0; r < R; r += 1) {
|
|
|
|
|
|
const t = tableDe[p * R + r];
|
|
|
|
|
|
if (t === RESERVE || visites[t] === 0) continue;
|
|
|
|
|
|
const imposesTable = Math.max(0, reservees[t] - 1);
|
|
|
|
|
|
imposes += imposesTable;
|
|
|
|
|
|
choisis += visites[t] - 1 - imposesTable;
|
|
|
|
|
|
visites[t] = 0;
|
|
|
|
|
|
reservees[t] = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
toursAssis.push(assis);
|
|
|
|
|
|
retoursChoisis.push(choisis);
|
|
|
|
|
|
retoursImposes.push(imposes);
|
|
|
|
|
|
}
|
|
|
|
|
|
return { toursAssis, retoursChoisis, retoursImposes };
|
|
|
|
|
|
}
|
|
|
|
|
|
|
[IMP] engine: single owners, regeneration, property grid
The search recomputed the collision excess and the gaps that the measure
already gives — two arithmetics for one quantity. It now reads them from
the measure, and the redundancy total has one owner. Contract values, the
indexed-plan guard and the population split are defined once. regenerer
rebuilds a proposition from its derived seed, stop count and history
length, which the spec now lists (§ 8.9). A property grid runs seeded
random rooms through the whole chain.
Checked: 435 node and 20 long tests; redefining the excess or the gaps in
the measure now fails the search tests too.
--- FR ---
[IMP] moteur : propriétaires uniques, régénération, grille de propriétés
La recherche recalculait l'excédent de collisions et les écarts que la
mesure donne déjà — deux arithmétiques pour une grandeur. Elle les lit
désormais dans la mesure, et le total de redondance a un seul
propriétaire. Valeurs du contrat, garde du plan indexé et partition des
populations sont définies une fois. regenerer reconstruit une proposition
depuis sa graine dérivée, son arrêt et la longueur de son historique,
que le spec énumère désormais (§ 8.9). Une grille de propriétés fait
traverser toute la chaîne à des salles tirées d'une graine.
Vérifié : 435 épreuves node et 20 longues ; redéfinir l'excédent ou les
écarts dans la mesure fait désormais tomber aussi la recherche.
Assisted-by: Claude Opus 5.5
2026-10-06 04:23:02 -04:00
|
|
|
|
// Population sans membre. min reste null tant qu'aucune valeur n'y entre :
|
|
|
|
|
|
// aucun Infinity ne sert de minimum initial.
|
|
|
|
|
|
const VIDE = Object.freeze({ min: null, somme: 0, effectif: 0 });
|
|
|
|
|
|
|
|
|
|
|
|
// La population, une valeur de plus ; celle qu'elle reçoit reste intacte.
|
|
|
|
|
|
const ajouter = ({ min, somme, effectif }, valeur) => ({
|
|
|
|
|
|
min: min === null || valeur < min ? valeur : min,
|
|
|
|
|
|
somme: somme + valeur,
|
|
|
|
|
|
effectif: effectif + 1,
|
|
|
|
|
|
});
|
[ADD] engine: indicators measured by full recomputation
Full recomputation is the measure every displayed figure comes from
(§ 5.10). It keeps the three collision units apart — cumulative
occurrences, distinct pairs, their excess — splits table returns and
repeated meetings into those the engine chose and those the reservations
impose, and gives null, never zero, for an empty population.
Checked: the small demonstration's perfect plan gives 8 met, A = 2,
r = 6, d = 0.25 for all twelve; spread and concentrated plans give
excess 0 and 4.
--- FR ---
[ADD] moteur : indicateurs mesurés par recalcul complet
Le recalcul complet est la mesure dont sort tout chiffre affiché
(§ 5.10). Il tient séparées les trois unités de collision — occurrences
cumulées, paires distinctes, leur excédent —, partage les retours à une
table et les rencontres répétées entre ceux que le moteur a choisis et
ceux qu'imposent les réservations, et rend null, jamais zéro, pour une
population vide.
Vérifié : le plan parfait de la petite démonstration donne 8 rencontres,
A = 2, r = 6, d = 0,25 pour les douze ; plans réparti et concentré
donnent un excédent de 0 et de 4.
Assisted-by: Claude Opus 5.5
2026-10-05 17:27:34 -04:00
|
|
|
|
|
|
|
|
|
|
// Agrégat d'une population ; la moyenne d'une population vide vaut null.
|
|
|
|
|
|
const conclure = ({ min, somme, effectif }) => ({
|
|
|
|
|
|
min,
|
|
|
|
|
|
moyenne: effectif === 0 ? null : somme / effectif,
|
|
|
|
|
|
effectif,
|
|
|
|
|
|
});
|
|
|
|
|
|
|
[IMP] engine: single owners, regeneration, property grid
The search recomputed the collision excess and the gaps that the measure
already gives — two arithmetics for one quantity. It now reads them from
the measure, and the redundancy total has one owner. Contract values, the
indexed-plan guard and the population split are defined once. regenerer
rebuilds a proposition from its derived seed, stop count and history
length, which the spec now lists (§ 8.9). A property grid runs seeded
random rooms through the whole chain.
Checked: 435 node and 20 long tests; redefining the excess or the gaps in
the measure now fails the search tests too.
--- FR ---
[IMP] moteur : propriétaires uniques, régénération, grille de propriétés
La recherche recalculait l'excédent de collisions et les écarts que la
mesure donne déjà — deux arithmétiques pour une grandeur. Elle les lit
désormais dans la mesure, et le total de redondance a un seul
propriétaire. Valeurs du contrat, garde du plan indexé et partition des
populations sont définies une fois. regenerer reconstruit une proposition
depuis sa graine dérivée, son arrêt et la longueur de son historique,
que le spec énumère désormais (§ 8.9). Une grille de propriétés fait
traverser toute la chaîne à des salles tirées d'une graine.
Vérifié : 435 épreuves node et 20 longues ; redéfinir l'excédent ou les
écarts dans la mesure fait désormais tomber aussi la recherche.
Assisted-by: Claude Opus 5.5
2026-10-06 04:23:02 -04:00
|
|
|
|
// Minimum, moyenne et effectif de valeurs[p] sur les trois populations du
|
|
|
|
|
|
// § 5.4, que replierParPopulation forme.
|
[ADD] engine: indicators measured by full recomputation
Full recomputation is the measure every displayed figure comes from
(§ 5.10). It keeps the three collision units apart — cumulative
occurrences, distinct pairs, their excess — splits table returns and
repeated meetings into those the engine chose and those the reservations
impose, and gives null, never zero, for an empty population.
Checked: the small demonstration's perfect plan gives 8 met, A = 2,
r = 6, d = 0.25 for all twelve; spread and concentrated plans give
excess 0 and 4.
--- FR ---
[ADD] moteur : indicateurs mesurés par recalcul complet
Le recalcul complet est la mesure dont sort tout chiffre affiché
(§ 5.10). Il tient séparées les trois unités de collision — occurrences
cumulées, paires distinctes, leur excédent —, partage les retours à une
table et les rencontres répétées entre ceux que le moteur a choisis et
ceux qu'imposent les réservations, et rend null, jamais zéro, pour une
population vide.
Vérifié : le plan parfait de la petite démonstration donne 8 rencontres,
A = 2, r = 6, d = 0,25 pour les douze ; plans réparti et concentré
donnent un excédent de 0 et de 4.
Assisted-by: Claude Opus 5.5
2026-10-05 17:27:34 -04:00
|
|
|
|
function troisAgregats(valeurs, statut) {
|
[IMP] engine: single owners, regeneration, property grid
The search recomputed the collision excess and the gaps that the measure
already gives — two arithmetics for one quantity. It now reads them from
the measure, and the redundancy total has one owner. Contract values, the
indexed-plan guard and the population split are defined once. regenerer
rebuilds a proposition from its derived seed, stop count and history
length, which the spec now lists (§ 8.9). A property grid runs seeded
random rooms through the whole chain.
Checked: 435 node and 20 long tests; redefining the excess or the gaps in
the measure now fails the search tests too.
--- FR ---
[IMP] moteur : propriétaires uniques, régénération, grille de propriétés
La recherche recalculait l'excédent de collisions et les écarts que la
mesure donne déjà — deux arithmétiques pour une grandeur. Elle les lit
désormais dans la mesure, et le total de redondance a un seul
propriétaire. Valeurs du contrat, garde du plan indexé et partition des
populations sont définies une fois. regenerer reconstruit une proposition
depuis sa graine dérivée, son arrêt et la longueur de son historique,
que le spec énumère désormais (§ 8.9). Une grille de propriétés fait
traverser toute la chaîne à des salles tirées d'une graine.
Vérifié : 435 épreuves node et 20 longues ; redéfinir l'excédent ou les
écarts dans la mesure fait désormais tomber aussi la recherche.
Assisted-by: Claude Opus 5.5
2026-10-06 04:23:02 -04:00
|
|
|
|
const { tous, mobiles, ancres } = replierParPopulation(valeurs, statut, VIDE, ajouter);
|
[ADD] engine: indicators measured by full recomputation
Full recomputation is the measure every displayed figure comes from
(§ 5.10). It keeps the three collision units apart — cumulative
occurrences, distinct pairs, their excess — splits table returns and
repeated meetings into those the engine chose and those the reservations
impose, and gives null, never zero, for an empty population.
Checked: the small demonstration's perfect plan gives 8 met, A = 2,
r = 6, d = 0.25 for all twelve; spread and concentrated plans give
excess 0 and 4.
--- FR ---
[ADD] moteur : indicateurs mesurés par recalcul complet
Le recalcul complet est la mesure dont sort tout chiffre affiché
(§ 5.10). Il tient séparées les trois unités de collision — occurrences
cumulées, paires distinctes, leur excédent —, partage les retours à une
table et les rencontres répétées entre ceux que le moteur a choisis et
ceux qu'imposent les réservations, et rend null, jamais zéro, pour une
population vide.
Vérifié : le plan parfait de la petite démonstration donne 8 rencontres,
A = 2, r = 6, d = 0,25 pour les douze ; plans réparti et concentré
donnent un excédent de 0 et de 4.
Assisted-by: Claude Opus 5.5
2026-10-05 17:27:34 -04:00
|
|
|
|
return { tous: conclure(tous), mobiles: conclure(mobiles), ancres: conclure(ancres) };
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const somme = (valeurs) => valeurs.reduce((total, valeur) => total + valeur, 0);
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Mesure complète d'un plan indexé : la mesure qui fait foi (§ 5.10). Ne
|
[IMP] engine: single owners, regeneration, property grid
The search recomputed the collision excess and the gaps that the measure
already gives — two arithmetics for one quantity. It now reads them from
the measure, and the redundancy total has one owner. Contract values, the
indexed-plan guard and the population split are defined once. regenerer
rebuilds a proposition from its derived seed, stop count and history
length, which the spec now lists (§ 8.9). A property grid runs seeded
random rooms through the whole chain.
Checked: 435 node and 20 long tests; redefining the excess or the gaps in
the measure now fails the search tests too.
--- FR ---
[IMP] moteur : propriétaires uniques, régénération, grille de propriétés
La recherche recalculait l'excédent de collisions et les écarts que la
mesure donne déjà — deux arithmétiques pour une grandeur. Elle les lit
désormais dans la mesure, et le total de redondance a un seul
propriétaire. Valeurs du contrat, garde du plan indexé et partition des
populations sont définies une fois. regenerer reconstruit une proposition
depuis sa graine dérivée, son arrêt et la longueur de son historique,
que le spec énumère désormais (§ 8.9). Une grille de propriétés fait
traverser toute la chaîne à des salles tirées d'une graine.
Vérifié : 435 épreuves node et 20 longues ; redéfinir l'excédent ou les
écarts dans la mesure fait désormais tomber aussi la recherche.
Assisted-by: Claude Opus 5.5
2026-10-06 04:23:02 -04:00
|
|
|
|
* modifie ni l'instance ni le plan. Lève ce que lève exigerPlanIndexe
|
|
|
|
|
|
* (configuration.js) avant de lire une case : une case manquante ou d'une
|
|
|
|
|
|
* autre forme lèverait plus loin une erreur qui ne nommerait ni la personne
|
|
|
|
|
|
* ni le tour.
|
[ADD] engine: indicators measured by full recomputation
Full recomputation is the measure every displayed figure comes from
(§ 5.10). It keeps the three collision units apart — cumulative
occurrences, distinct pairs, their excess — splits table returns and
repeated meetings into those the engine chose and those the reservations
impose, and gives null, never zero, for an empty population.
Checked: the small demonstration's perfect plan gives 8 met, A = 2,
r = 6, d = 0.25 for all twelve; spread and concentrated plans give
excess 0 and 4.
--- FR ---
[ADD] moteur : indicateurs mesurés par recalcul complet
Le recalcul complet est la mesure dont sort tout chiffre affiché
(§ 5.10). Il tient séparées les trois unités de collision — occurrences
cumulées, paires distinctes, leur excédent —, partage les retours à une
table et les rencontres répétées entre ceux que le moteur a choisis et
ceux qu'imposent les réservations, et rend null, jamais zéro, pour une
population vide.
Vérifié : le plan parfait de la petite démonstration donne 8 rencontres,
A = 2, r = 6, d = 0,25 pour les douze ; plans réparti et concentré
donnent un excédent de 0 et de 4.
Assisted-by: Claude Opus 5.5
2026-10-05 17:27:34 -04:00
|
|
|
|
*
|
|
|
|
|
|
* @param {import('./types.js').Instance} instance
|
[IMP] engine: single owners, regeneration, property grid
The search recomputed the collision excess and the gaps that the measure
already gives — two arithmetics for one quantity. It now reads them from
the measure, and the redundancy total has one owner. Contract values, the
indexed-plan guard and the population split are defined once. regenerer
rebuilds a proposition from its derived seed, stop count and history
length, which the spec now lists (§ 8.9). A property grid runs seeded
random rooms through the whole chain.
Checked: 435 node and 20 long tests; redefining the excess or the gaps in
the measure now fails the search tests too.
--- FR ---
[IMP] moteur : propriétaires uniques, régénération, grille de propriétés
La recherche recalculait l'excédent de collisions et les écarts que la
mesure donne déjà — deux arithmétiques pour une grandeur. Elle les lit
désormais dans la mesure, et le total de redondance a un seul
propriétaire. Valeurs du contrat, garde du plan indexé et partition des
populations sont définies une fois. regenerer reconstruit une proposition
depuis sa graine dérivée, son arrêt et la longueur de son historique,
que le spec énumère désormais (§ 8.9). Une grille de propriétés fait
traverser toute la chaîne à des salles tirées d'une graine.
Vérifié : 435 épreuves node et 20 longues ; redéfinir l'excédent ou les
écarts dans la mesure fait désormais tomber aussi la recherche.
Assisted-by: Claude Opus 5.5
2026-10-06 04:23:02 -04:00
|
|
|
|
* @param {ArrayLike<number>} tableDe tableDe[p * R + r] = index de table, RESERVE pour la réserve
|
[ADD] engine: indicators measured by full recomputation
Full recomputation is the measure every displayed figure comes from
(§ 5.10). It keeps the three collision units apart — cumulative
occurrences, distinct pairs, their excess — splits table returns and
repeated meetings into those the engine chose and those the reservations
impose, and gives null, never zero, for an empty population.
Checked: the small demonstration's perfect plan gives 8 met, A = 2,
r = 6, d = 0.25 for all twelve; spread and concentrated plans give
excess 0 and 4.
--- FR ---
[ADD] moteur : indicateurs mesurés par recalcul complet
Le recalcul complet est la mesure dont sort tout chiffre affiché
(§ 5.10). Il tient séparées les trois unités de collision — occurrences
cumulées, paires distinctes, leur excédent —, partage les retours à une
table et les rencontres répétées entre ceux que le moteur a choisis et
ceux qu'imposent les réservations, et rend null, jamais zéro, pour une
population vide.
Vérifié : le plan parfait de la petite démonstration donne 8 rencontres,
A = 2, r = 6, d = 0,25 pour les douze ; plans réparti et concentré
donnent un excédent de 0 et de 4.
Assisted-by: Claude Opus 5.5
2026-10-05 17:27:34 -04:00
|
|
|
|
* @returns {Mesures}
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function mesurer(instance, tableDe) {
|
[IMP] engine: single owners, regeneration, property grid
The search recomputed the collision excess and the gaps that the measure
already gives — two arithmetics for one quantity. It now reads them from
the measure, and the redundancy total has one owner. Contract values, the
indexed-plan guard and the population split are defined once. regenerer
rebuilds a proposition from its derived seed, stop count and history
length, which the spec now lists (§ 8.9). A property grid runs seeded
random rooms through the whole chain.
Checked: 435 node and 20 long tests; redefining the excess or the gaps in
the measure now fails the search tests too.
--- FR ---
[IMP] moteur : propriétaires uniques, régénération, grille de propriétés
La recherche recalculait l'excédent de collisions et les écarts que la
mesure donne déjà — deux arithmétiques pour une grandeur. Elle les lit
désormais dans la mesure, et le total de redondance a un seul
propriétaire. Valeurs du contrat, garde du plan indexé et partition des
populations sont définies une fois. regenerer reconstruit une proposition
depuis sa graine dérivée, son arrêt et la longueur de son historique,
que le spec énumère désormais (§ 8.9). Une grille de propriétés fait
traverser toute la chaîne à des salles tirées d'une graine.
Vérifié : 435 épreuves node et 20 longues ; redéfinir l'excédent ou les
écarts dans la mesure fait désormais tomber aussi la recherche.
Assisted-by: Claude Opus 5.5
2026-10-06 04:23:02 -04:00
|
|
|
|
exigerPlanIndexe(instance, tableDe);
|
[ADD] engine: indicators measured by full recomputation
Full recomputation is the measure every displayed figure comes from
(§ 5.10). It keeps the three collision units apart — cumulative
occurrences, distinct pairs, their excess — splits table returns and
repeated meetings into those the engine chose and those the reservations
impose, and gives null, never zero, for an empty population.
Checked: the small demonstration's perfect plan gives 8 met, A = 2,
r = 6, d = 0.25 for all twelve; spread and concentrated plans give
excess 0 and 4.
--- FR ---
[ADD] moteur : indicateurs mesurés par recalcul complet
Le recalcul complet est la mesure dont sort tout chiffre affiché
(§ 5.10). Il tient séparées les trois unités de collision — occurrences
cumulées, paires distinctes, leur excédent —, partage les retours à une
table et les rencontres répétées entre ceux que le moteur a choisis et
ceux qu'imposent les réservations, et rend null, jamais zéro, pour une
population vide.
Vérifié : le plan parfait de la petite démonstration donne 8 rencontres,
A = 2, r = 6, d = 0,25 pour les douze ; plans réparti et concentré
donnent un excédent de 0 et de 4.
Assisted-by: Claude Opus 5.5
2026-10-05 17:27:34 -04:00
|
|
|
|
const { N, groupe, groupes, statut } = instance;
|
|
|
|
|
|
const paires = lirePaires(instance, compterRencontres(instance, tableDe));
|
|
|
|
|
|
const { collisions, distinctes } = paires;
|
|
|
|
|
|
|
|
|
|
|
|
const rencontres = Array.from(paires.rencontres);
|
|
|
|
|
|
const affilies = Array.from(paires.affilies);
|
|
|
|
|
|
const appartenancesVues = Array.from(paires.vues);
|
|
|
|
|
|
const redondance = affilies.map((f, p) => f - appartenancesVues[p]);
|
|
|
|
|
|
const diversite = affilies.map((f, p) => (f === 0 ? null : appartenancesVues[p] / f));
|
|
|
|
|
|
|
|
|
|
|
|
const effectifs = new Array(groupes.length).fill(0);
|
|
|
|
|
|
for (let p = 0; p < N; p += 1) {
|
|
|
|
|
|
if (groupe[p] !== SANS_GROUPE) effectifs[groupe[p]] += 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
const parGroupe = groupes.map((libelle, g) => ({
|
|
|
|
|
|
groupe: libelle,
|
|
|
|
|
|
effectif: effectifs[g],
|
|
|
|
|
|
collisionsCumulees: collisions[g],
|
|
|
|
|
|
pairesDistinctes: distinctes[g],
|
|
|
|
|
|
excedent: collisions[g] - distinctes[g],
|
|
|
|
|
|
}));
|
|
|
|
|
|
const collisionsCumulees = somme(collisions);
|
|
|
|
|
|
const pairesDistinctes = somme(distinctes);
|
|
|
|
|
|
|
|
|
|
|
|
const { toursAssis, retoursChoisis, retoursImposes } = compterRetours(instance, tableDe);
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
rencontres,
|
|
|
|
|
|
affilies,
|
|
|
|
|
|
appartenancesVues,
|
|
|
|
|
|
redondance,
|
|
|
|
|
|
diversite,
|
|
|
|
|
|
toursAssis,
|
|
|
|
|
|
retoursChoisis,
|
|
|
|
|
|
retoursImposes,
|
|
|
|
|
|
aggRencontres: troisAgregats(rencontres, statut),
|
|
|
|
|
|
aggRedondance: troisAgregats(redondance, statut),
|
[IMP] engine: single owners, regeneration, property grid
The search recomputed the collision excess and the gaps that the measure
already gives — two arithmetics for one quantity. It now reads them from
the measure, and the redundancy total has one owner. Contract values, the
indexed-plan guard and the population split are defined once. regenerer
rebuilds a proposition from its derived seed, stop count and history
length, which the spec now lists (§ 8.9). A property grid runs seeded
random rooms through the whole chain.
Checked: 435 node and 20 long tests; redefining the excess or the gaps in
the measure now fails the search tests too.
--- FR ---
[IMP] moteur : propriétaires uniques, régénération, grille de propriétés
La recherche recalculait l'excédent de collisions et les écarts que la
mesure donne déjà — deux arithmétiques pour une grandeur. Elle les lit
désormais dans la mesure, et le total de redondance a un seul
propriétaire. Valeurs du contrat, garde du plan indexé et partition des
populations sont définies une fois. regenerer reconstruit une proposition
depuis sa graine dérivée, son arrêt et la longueur de son historique,
que le spec énumère désormais (§ 8.9). Une grille de propriétés fait
traverser toute la chaîne à des salles tirées d'une graine.
Vérifié : 435 épreuves node et 20 longues ; redéfinir l'excédent ou les
écarts dans la mesure fait désormais tomber aussi la recherche.
Assisted-by: Claude Opus 5.5
2026-10-06 04:23:02 -04:00
|
|
|
|
totalRedondance: somme(redondance),
|
[ADD] engine: indicators measured by full recomputation
Full recomputation is the measure every displayed figure comes from
(§ 5.10). It keeps the three collision units apart — cumulative
occurrences, distinct pairs, their excess — splits table returns and
repeated meetings into those the engine chose and those the reservations
impose, and gives null, never zero, for an empty population.
Checked: the small demonstration's perfect plan gives 8 met, A = 2,
r = 6, d = 0.25 for all twelve; spread and concentrated plans give
excess 0 and 4.
--- FR ---
[ADD] moteur : indicateurs mesurés par recalcul complet
Le recalcul complet est la mesure dont sort tout chiffre affiché
(§ 5.10). Il tient séparées les trois unités de collision — occurrences
cumulées, paires distinctes, leur excédent —, partage les retours à une
table et les rencontres répétées entre ceux que le moteur a choisis et
ceux qu'imposent les réservations, et rend null, jamais zéro, pour une
population vide.
Vérifié : le plan parfait de la petite démonstration donne 8 rencontres,
A = 2, r = 6, d = 0,25 pour les douze ; plans réparti et concentré
donnent un excédent de 0 et de 4.
Assisted-by: Claude Opus 5.5
2026-10-05 17:27:34 -04:00
|
|
|
|
collisionsCumulees,
|
|
|
|
|
|
pairesDistinctes,
|
|
|
|
|
|
excedentCollisions: collisionsCumulees - pairesDistinctes,
|
|
|
|
|
|
rencontresRepetees: paires.rencontresRepetees,
|
|
|
|
|
|
maxRencontresPaire: paires.maxRencontresPaire,
|
|
|
|
|
|
totalRetoursChoisis: somme(retoursChoisis),
|
|
|
|
|
|
totalRetoursImposes: somme(retoursImposes),
|
|
|
|
|
|
parGroupe,
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|