Pular para o conteúdo
DispatchAtlas
Buscar

Tutoriais

Estes tutoriais são percursos orientados-ao-aprendizado, de ponta-a-ponta: cada passo é um script executável, cada saída mostrada é saída real dos dados de fumaça empacotados, e cada execução é determinística — as mesmas sementes produzem os mesmos números na sua máquina. Complete primeiro a instalação e o início rápido, depois execute cada script a partir do checkout do repositório com uv run python <file>.py.

🧭 Escolha Um Tutorial

TutorialVocê aprenderáPacotes tocados
Modelar e resolver um primeiro problema de despachoEscolher uma instância de benchmark, executar dois solvers sobre ela, comparar escalonamentos, e ler metadados de solver.dispatchatlas.core, dispatchatlas.bench, dispatchatlas.solve
Executar uma campanha pequena e ler seus resultadosConfigurar uma campanha com-checkpoints, executá-la em um workspace, e carregar os resultados para análise.dispatchatlas.lab, dispatchatlas.analytica

Caminhos de referência mais profundos continuam onde os tutoriais terminam: contratos de domínio para o modelo de escalonamento, modelo de benchmarks para a geração do catálogo, sistema de solvers para o registro completo, motor de campanhas para o detalhe de orquestração, e exportações de análise para os pacotes de evidência. Campanhas maiores requerem os gates estatísticos e de lançamento descritos em prontidão.

🛠️ Tutorial 1: Modelar E Resolver Um Primeiro Problema De Despacho

O início rápido resolveu um problema com um solver. Este tutorial vai um nível mais fundo: você escolhe uma instância de benchmark específica, executa duas linhas-base de despacho sobre ela, compara os escalonamentos que elas constroem, e lê os metadados que explicam cada solver.

1️⃣ Ver o que o catálogo de fumaça oferece

O catálogo de fumaça empacotado materializa duas pequenas instâncias determinísticas por família de escalonamento a partir de uma única semente raiz. Salve isto como list_problems.py e execute-o com 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)

Saída:

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-1

Cada id nomeia sua família de escalonamento e um índice de instância baseado-em-zero. O resto do tutorial usa smoke-job-shop-0.

2️⃣ Executar dois solvers sobre uma instância

provider.get_problem recebe um ProblemId e retorna um ValidatedProblem — a especificação do problema mais seu selo e relatório de validação, de modo que um solver nunca recebe uma instância não-validada. Os dois solvers abaixo são linhas-base de despacho determinísticas: earliest-start escalona tarefas em ordem topológica de entrada, enquanto shortest-processing-time prioriza tarefas mais curtas. Salve isto como 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}"
    )

Execute-o com 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.0

Ambos os escalonamentos são factíveis, e nesta instância vence a regra mais simples: earliest-start termina em 353.0 enquanto shortest-processing-time, que prioriza as tarefas mais curtas, termina em 433.0. Vale a pena parar aqui, porque shortest-processing-time é uma boa regra em geral — num job shop ela pode adiar uma tarefa longa que uma tarefa posterior está esperando, e o escalonamento inteiro espera junto. A reputação de uma regra não diz o que ela faz na sua instância.

E é justamente esse o ponto: a forma, não o número. Uma instância não prova nada em nenhuma direção — é para isso que servem as campanhas e os métodos estatísticos — mas a comparação aqui (mesmo problema validado, mesmos critérios de parada, mesma semente derivada) é exatamente como evidência maior é construída, e uma única execução é exatamente o que ela não é.

3️⃣ Ler os metadados do solver

Cada solver registrado carrega metadados como seu contrato público: objetivos suportados, rótulos de capacidade, estocasticidade, critérios de parada padrão, e uma citação canônica. Salve isto como 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))

Execute-o com 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, deterministic

Estes metadados são sobre o que registry.select filtra e a partir do que o recomendador de solvers explica. O registro completo — linhas-base, metaheurísticas, adaptadores exatos, e a família NDSO — está catalogado em algoritmos e sistema de solvers.

🧪 Tutorial 2: Executar Uma Campanha Pequena E Ler Seus Resultados

Uma campanha é um conjunto configurado de execuções — instâncias de benchmark cruzadas com solvers e objetivos — executado com sementes, orçamentos, checkpoints explícitos, e um repositório de resultados em-disco. Este tutorial executa a mesma forma que a receita rastreada em experiments/configs/smoke-pilot.json: duas instâncias de fumaça, duas linhas-base determinísticas, um objetivo.

1️⃣ Configurar e executar a campanha

Salve isto como first_campaign.py. Ele declara a campanha, valida-a em um plano determinístico, estima seu custo com uma execução-seca, então executa-a em um 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)}")

Execute-o com uv run python first_campaign.py:

planned runs: 4
estimated wall time: 2.0s
completed runs: 4
failed attempts: 0

Quatro execuções é exatamente o produto cruzado: 2 instâncias de benchmark × 2 solvers × 1 objetivo, com uma execução por célula porque ambos os solvers são determinísticos. A semente de cada execução deriva de root_seed e da posição da execução, de modo que re-executar o script reproduz os mesmos registros; o checkpoint deixa uma campanha interrompida retomar sem repetir trabalho concluído.

2️⃣ Inspecionar o que aterrissou no disco

O runner escreveu um workspace com a mesma disposição que o workspace de experimentos rastreado:

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.json

Um registro JSON por execução, endereçado por campanha, solver, benchmark, e índice de réplica — o caminho em si é o índice. Cada registro é hasheado-por-conteúdo sobre sua carga determinística, que é contra o que o modo replay verifica.

3️⃣ Carregar os resultados para análise

dispatchatlas.analytica lê diretórios de campanha concluídos sem importar o runtime de campanha. Salve isto como 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}"
    )

Execute-o com 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.1

summarize_dataset computa estatísticas descritivas por solver e objetivo. Com apenas duas execuções por solver os métodos inferenciais (testes de significância, intervalos de confiança) roteiam para a superfície de limitações em vez de produzir resultados sub-potenciados — o piso de potência-estatística de 30 execuções independentes por célula estocástica solver-instância é descrito em exportações de análise.

4️⃣ Exportar um pacote de evidência (opcional)

O mesmo diretório de campanha alimenta o comando de exportação, que escreve um pacote de evidência filtrado-por-divulgação de tabelas, figuras, e suplemento:

uv run dispatchatlas export `
  --campaign-dir .\my-campaigns\results\first-campaign `
  --target-dir .\exports\first-campaign `
  --authorized-output-root .\exports `
  --tier core

O pacote aterrissa em exports/first-campaign/evidence-bundles/first-campaign-core/. A página pacotes de evidência explica os quatro níveis e o conteúdo do pacote.

🎓 Para onde isto leva

  • A receita rastreada experiments/scripts/run_smoke_pilot.py executa esta mesma forma no workspace de experimentos e serializa sua configuração para a interface de linha-de-comando dispatchatlas-lab.
  • A página motor de campanhas cobre modos de execução, política de retentativa, retomada, verificação de replay, protocolos de parada duais, e garantias de comparação-justa.
  • Campanhas de estágio-completo permanecem bloqueadas até que a aprovação do design estatístico seja registrada — ver prontidão de lançamento.