Tutoriels
Ces tutoriels sont des parcours orientés-apprentissage, de bout-en-bout : chaque étape est
un script exécutable, chaque sortie montrée est une sortie réelle des données de test
empaquetées, et chaque exécution est déterministe — les mêmes graines produisent les mêmes
nombres sur votre machine. Complétez d'abord l'installation
et le démarrage rapide, puis exécutez chaque script
depuis le checkout du dépôt avec uv run python <file>.py.
🧭 Choisissez Un Tutoriel
| Tutoriel | Vous apprendrez | Paquets touchés |
|---|---|---|
| Modéliser et résoudre un premier problème de répartition | Choisir une instance de benchmark, exécuter deux solveurs dessus, comparer les horaires, et lire les métadonnées de solveur. | dispatchatlas.core, dispatchatlas.bench, dispatchatlas.solve |
| Exécuter une petite campagne et lire ses résultats | Configurer une campagne avec-points-de-contrôle, l'exécuter dans un workspace, et charger les résultats pour analyse. | dispatchatlas.lab, dispatchatlas.analytica |
Des chemins de référence plus profonds continuent là où les tutoriels finissent : contrats de domaine pour le modèle de planification, modèle de benchmarks pour la génération du catalogue, système de solveurs pour le registre complet, moteur de campagnes pour le détail d'orchestration, et exportations d'analyse pour les lots de preuves. Les campagnes plus grandes requièrent les gates statistiques et de publication décrits dans préparation.
🛠️ Tutoriel 1 : Modéliser Et Résoudre Un Premier Problème De Répartition
Le démarrage rapide a résolu un problème avec un solveur. Ce tutoriel va un niveau plus profond : vous choisissez une instance de benchmark spécifique, exécutez deux lignes-de-base de répartition dessus, comparez les horaires qu'elles construisent, et lisez les métadonnées qui expliquent chaque solveur.
1️⃣ Voir ce qu'offre le catalogue de test
Le catalogue de test empaqueté matérialise deux petites instances déterministes par famille
de planification depuis une seule graine racine. Sauvegardez ceci comme list_problems.py
et exécutez-le avec uv run python list_problems.py :
from dispatchatlas.bench import smoke_benchmark_provider
provider = smoke_benchmark_provider(root_seed=20260527)
for problem_id in provider.list_problem_ids():
print(problem_id.value)Sortie :
smoke-cloud-edge-0
smoke-cloud-edge-1
smoke-workflow-0
smoke-workflow-1
smoke-machine-scheduling-unrelated-0
smoke-machine-scheduling-unrelated-1
smoke-job-shop-0
smoke-job-shop-1
smoke-flexible-job-shop-0
smoke-flexible-job-shop-1
smoke-permutation-flow-shop-0
smoke-permutation-flow-shop-1
smoke-setup-flow-shop-0
smoke-setup-flow-shop-1
smoke-rcpsp-renewable-0
smoke-rcpsp-renewable-1
smoke-open-shop-0
smoke-open-shop-1
smoke-hybrid-flow-shop-0
smoke-hybrid-flow-shop-1
smoke-distributed-permutation-flow-shop-0
smoke-distributed-permutation-flow-shop-1
smoke-no-wait-flow-shop-0
smoke-no-wait-flow-shop-1
smoke-blocking-flow-shop-0
smoke-blocking-flow-shop-1
smoke-distributed-assembly-flow-shop-0
smoke-distributed-assembly-flow-shop-1
smoke-multi-objective-pfsp-0
smoke-multi-objective-pfsp-1
smoke-rcpsp-max-0
smoke-rcpsp-max-1
smoke-rcpsp-multi-mode-0
smoke-rcpsp-multi-mode-1
smoke-multi-project-rcpsp-0
smoke-multi-project-rcpsp-1
smoke-unrelated-parallel-setup-0
smoke-unrelated-parallel-setup-1
smoke-reentrant-fab-0
smoke-reentrant-fab-1
smoke-distributed-flexible-job-shop-0
smoke-distributed-flexible-job-shop-1
smoke-facility-assignment-0
smoke-facility-assignment-1Chaque id nomme sa famille de planification et un index d'instance
basé-sur-zéro. Le reste du tutoriel utilise smoke-job-shop-0.
2️⃣ Exécuter deux solveurs sur une instance
provider.get_problem prend un ProblemId et retourne un ValidatedProblem — la
spécification du problème plus son tampon et rapport de validation, de sorte qu'un solveur
ne reçoit jamais une instance non-validée. Les deux solveurs ci-dessous sont des
lignes-de-base de répartition déterministes : earliest-start planifie les tâches en ordre
topologique d'entrée, tandis que shortest-processing-time priorise les tâches plus courtes.
Sauvegardez ceci comme compare_solvers.py :
from dispatchatlas.bench import smoke_benchmark_provider
from dispatchatlas.core import ProblemId, TerminationPolicy, derive_seed
from dispatchatlas.solve import default_solver_registry
provider = smoke_benchmark_provider(root_seed=20260527)
validated = provider.get_problem(ProblemId("smoke-job-shop-0"))
spec = validated.spec
print(f"problem: {spec.id.value}")
print(f"tasks: {len(spec.tasks)} resources: {len(spec.resources)}")
registry = default_solver_registry()
for solver_id in ("earliest-start", "shortest-processing-time"):
metadata = registry.get_metadata(solver_id)
solver = registry.create(solver_id)
run = solver.solve(
problem=validated,
stop=TerminationPolicy(max_iterations=metadata.default_stop.max_iterations),
seed=derive_seed(20260610, "docs.tutorial.compare", 0),
)
makespan = run.result.objective_values[0]
print(
f"{solver_id}: feasible={run.result.feasible} "
f"{makespan.objective_name}={makespan.value:.1f}"
)Exécutez-le avec uv run python compare_solvers.py :
problem: smoke-job-shop-0
tasks: 9 resources: 3
earliest-start: feasible=True makespan=353.0
shortest-processing-time: feasible=True makespan=433.0Les deux horaires sont faisables, et sur cette instance c'est la règle la plus simple qui l'emporte : earliest-start finit à 353.0 tandis que shortest-processing-time, qui privilégie les tâches courtes, finit à 433.0. Cela mérite qu'on s'y arrête, car shortest-processing-time est une bonne règle en général — dans un job shop, elle peut différer une tâche longue qu'une tâche en aval attend, et tout l'horaire attend avec elle. La réputation d'une règle ne vous dit pas ce qu'elle fait sur votre instance.
Et c'est bien là l'intérêt de la forme plutôt que du chiffre. Une instance ne prouve rien dans un sens ni dans l'autre — c'est à cela que servent les campagnes et les méthodes statistiques — mais la comparaison ici (même problème validé, mêmes critères d'arrêt, même graine dérivée) est exactement comment une preuve plus grande est construite, et une exécution unique est exactement ce qu'elle n'est pas.
3️⃣ Lire les métadonnées du solveur
Chaque solveur enregistré porte des métadonnées comme son contrat public : objectifs
supportés, étiquettes de capacité, stochasticité, critères d'arrêt par défaut, et une
citation canonique. Sauvegardez ceci comme inspect_metadata.py :
from dispatchatlas.solve import default_solver_registry
registry = default_solver_registry()
metadata = registry.get_metadata("shortest-processing-time")
print(f"solver: {metadata.solver_id}")
print(f"stochasticity: {metadata.stochasticity}")
print(f"citation: {metadata.citation.reference}")
print("capabilities:", ", ".join(c.value for c in metadata.capabilities))Exécutez-le avec uv run python inspect_metadata.py :
solver: shortest-processing-time
stochasticity: deterministic
citation: Smith, W. E. (1956). Various optimizers for single-stage production. Naval Research Logistics Quarterly, 3(1-2), 59-66.
capabilities: single-objective, capacity-aware, precedence-aware, constructive, dispatching, deterministicCes métadonnées sont ce sur quoi registry.select filtre et ce à partir de quoi le
recommandeur de solveurs explique. Le registre complet —
lignes-de-base, métaheuristiques, adaptateurs exacts, et la famille NDSO — est catalogué dans
algorithmes et système de solveurs.
🧪 Tutoriel 2 : Exécuter Une Petite Campagne Et Lire Ses Résultats
Une campagne est un ensemble configuré d'exécutions — instances de benchmark croisées avec
solveurs et objectifs — exécuté avec des graines, budgets, points-de-contrôle explicites, et
un dépôt de résultats sur-disque. Ce tutoriel exécute la même forme que la recette suivie à
experiments/configs/smoke-pilot.json : deux instances de test, deux lignes-de-base
déterministes, un objectif.
1️⃣ Configurer et exécuter la campagne
Sauvegardez ceci comme first_campaign.py. Il déclare la campagne, la valide en un plan
déterministe, estime son coût avec une exécution-à-blanc, puis l'exécute dans un workspace
local my-campaigns/ :
from pathlib import Path
from dispatchatlas.core import TerminationPolicy
from dispatchatlas.lab import (
CampaignConfig,
CampaignKind,
CampaignStage,
ExecutionMode,
OutputPolicy,
ResourceBudget,
default_campaign_runner,
)
workspace = Path("my-campaigns")
config = CampaignConfig(
campaign_id="first-campaign",
benchmark_ids=("smoke-job-shop-0", "smoke-workflow-0"),
solver_ids=("earliest-start", "shortest-processing-time"),
objectives=("makespan",),
root_seed=20260610,
seed_namespace="docs.tutorial.first-campaign",
stop=TerminationPolicy(max_iterations=5),
output=OutputPolicy(root_dir=str(workspace)),
stage=CampaignStage.SMOKE,
kind=CampaignKind.PILOT,
resources=ResourceBudget(
max_workers=2,
max_concurrent_runs=2,
estimated_seconds_per_run=0.5,
),
execution_mode=ExecutionMode.SEQUENTIAL,
)
runner = default_campaign_runner(workspace)
plan = runner.validate(config)
budget = runner.dry_run(plan)
print(f"planned runs: {len(plan.runs)}")
print(f"estimated wall time: {budget.estimated_wall_time_seconds:.1f}s")
index = runner.run(plan)
print(f"completed runs: {index.run_count}")
print(f"failed attempts: {len(index.failures)}")Exécutez-le avec uv run python first_campaign.py :
planned runs: 4
estimated wall time: 2.0s
completed runs: 4
failed attempts: 0Quatre exécutions est exactement le produit croisé : 2 instances de benchmark × 2 solveurs ×
1 objectif, avec une exécution par cellule parce que les deux solveurs sont déterministes.
La graine de chaque exécution dérive de root_seed et de la position de l'exécution, de
sorte que ré-exécuter le script reproduit les mêmes enregistrements ; le point-de-contrôle
laisse une campagne interrompue reprendre sans répéter le travail achevé.
2️⃣ Inspecter ce qui a atterri sur disque
Le runner a écrit un workspace avec la même disposition que le workspace d'expériences suivi :
my-campaigns/
.checkpoints/first-campaign.json
ENVIRONMENT.md
logs/first-campaign_<timestamp>.log
results/first-campaign/
plan.json
environment.json
earliest-start/smoke-job-shop-0/run_0.json
earliest-start/smoke-workflow-0/run_0.json
shortest-processing-time/smoke-job-shop-0/run_0.json
shortest-processing-time/smoke-workflow-0/run_0.jsonUn enregistrement JSON par exécution, adressé par campagne, solveur, benchmark, et index de
réplique — le chemin lui-même est l'index. Chaque enregistrement est haché-par-contenu sur
sa charge déterministe, ce contre quoi le mode replay vérifie.
3️⃣ Charger les résultats pour analyse
dispatchatlas.analytica lit les répertoires de campagne achevés sans importer le runtime
de campagne. Sauvegardez ceci comme read_results.py :
from pathlib import Path
from dispatchatlas.analytica import load_result_dataset, summarize_dataset
dataset = load_result_dataset(Path("my-campaigns"), "first-campaign")
print(f"campaign: {dataset.campaign_id}")
print(f"completed runs: {len(dataset.completed)}")
summary = summarize_dataset(dataset)
for solver in summary.solver_summaries:
print(
f"{solver.solver_id}: runs={solver.count} "
f"feasible={solver.feasible_count} "
f"mean {solver.objective_name}={solver.mean:.1f}"
)Exécutez-le avec uv run python read_results.py :
campaign: first-campaign
completed runs: 4
earliest-start: runs=2 feasible=2 mean makespan=182.1
shortest-processing-time: runs=2 feasible=2 mean makespan=222.1summarize_dataset calcule des statistiques descriptives par solveur et objectif. Avec
seulement deux exécutions par solveur, les méthodes inférentielles (tests de signification,
intervalles de confiance) s'acheminent vers la surface des limitations au lieu de produire
des résultats sous-puissants — le plancher de puissance-statistique de 30 exécutions
indépendantes par cellule stochastique solveur-instance est décrit dans
exportations d'analyse.
4️⃣ Exporter un lot de preuves (optionnel)
Le même répertoire de campagne alimente la commande d'exportation, qui écrit un lot de preuves filtré-par-divulgation de tables, figures, et supplément :
uv run dispatchatlas export `
--campaign-dir .\my-campaigns\results\first-campaign `
--target-dir .\exports\first-campaign `
--authorized-output-root .\exports `
--tier coreLe lot atterrit à exports/first-campaign/evidence-bundles/first-campaign-core/. La page
lots de preuves explique les quatre niveaux et le contenu du lot.
🎓 Où cela mène
- La recette suivie
experiments/scripts/run_smoke_pilot.pyexécute cette même forme dans le workspace d'expériences et sérialise sa configuration pour l'interface en-ligne-de-commandedispatchatlas-lab. - La page moteur de campagnes couvre les modes d'exécution, la politique de réessai, la reprise, la vérification de replay, les protocoles d'arrêt duaux, et les garanties de comparaison-équitable.
- Les campagnes de phase-complète restent bloquées jusqu'à ce que l'approbation de la conception statistique soit enregistrée — voir préparation de publication.