튜토리얼
이 튜토리얼들은 학습-지향의 종단-간 워크입니다: 각 단계는 실행 가능한 스크립트이고, 보여지는
각 출력은 번들된 스모크 데이터로부터의 실제 출력이며, 각 실행은 결정론적입니다 — 같은 시드는
당신의 머신에서 같은 숫자를 산출합니다. 먼저 설치와
빠른 시작을 완료한 다음, 각 스크립트를 저장소 체크아웃에서
uv run python <file>.py로 실행하세요.
🧭 튜토리얼 선택
| 튜토리얼 | 배울 것 | 닿는 패키지 |
|---|---|---|
| 첫 디스패치 문제를 모델링하고 풀기 | 벤치마크 인스턴스를 고르고, 그 위에서 두 솔버를 실행하고, 스케줄을 비교하고, 솔버 메타데이터를 읽기. | dispatchatlas.core, dispatchatlas.bench, dispatchatlas.solve |
| 작은 캠페인을 실행하고 그 결과를 읽기 | 체크포인트된 캠페인을 구성하고, 워크스페이스로 실행하고, 분석을 위해 결과를 로드하기. | dispatchatlas.lab, dispatchatlas.analytica |
더 깊은 참조 경로는 튜토리얼이 끝나는 곳에서 계속됩니다: 도메인 계약은 스케줄링 모델을 위해, 벤치마크 모델은 카탈로그 생성을 위해, 솔버 시스템은 완전한 레지스트리를 위해, 캠페인 엔진은 오케스트레이션 세부를 위해, 분석 익스포트는 증거 번들을 위해. 더 큰 캠페인은 준비에서 기술된 통계 및 릴리스 게이트를 요합니다.
🛠️ Tutorial 1: 첫 디스패치 문제를 모델링하고 풀기
빠른 시작은 한 솔버로 한 문제를 풀었습니다. 이 튜토리얼은 한 단계 더 깊이 갑니다: 특정 벤치마크 인스턴스를 고르고, 그 위에서 두 디스패칭 베이스라인을 실행하고, 그것들이 구축하는 스케줄을 비교하고, 각 솔버를 설명하는 메타데이터를 읽습니다.
1️⃣ 스모크 카탈로그가 무엇을 제공하는지 보기
번들된 스모크 카탈로그는 단일 루트 시드로부터 스케줄링 패밀리당 두 개의 작은 결정론적 인스턴스를
물질화합니다. 이를 list_problems.py로 저장하고 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)출력:
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각 id는 그 스케줄링 패밀리와 영-기반 인스턴스 인덱스를 명명합니다.
튜토리얼 나머지는 smoke-job-shop-0을 사용합니다.
2️⃣ 한 인스턴스 위에서 두 솔버 실행하기
provider.get_problem은 ProblemId를 받아 ValidatedProblem을 반환합니다 — 문제 명세에 그
검증 스탬프와 보고서를 더한 것으로, 솔버가 결코 미-검증 인스턴스를 받지 않게 합니다. 아래 두
솔버는 결정론적 디스패칭 베이스라인입니다: earliest-start는 위상 입력 순서로 태스크를
스케줄링하고, shortest-processing-time은 더 짧은 태스크를 우선합니다. 이를
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}"
)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두 스케줄 모두 가능하며, 이 인스턴스에서는 더 단순한 규칙이 이깁니다. earliest-start는 353.0에 끝나고, 짧은 작업을 우선하는 shortest-processing-time은 433.0에 끝납니다. 여기서 한 번 멈춰 볼 만합니다. shortest-processing-time은 일반적으로 좋은 규칙이기 때문입니다 — 잡 숍에서는 후속 작업이 기다리고 있는 긴 작업을 미룰 수 있고, 그러면 스케줄 전체가 함께 기다립니다. 규칙의 평판은 그 규칙이 당신의 인스턴스에서 무엇을 하는지 말해 주지 않습니다.
그래서 숫자가 아니라 형태가 요점입니다. 한 인스턴스는 어느 쪽으로도 아무것도 증명하지 않습니다 — 그것이 캠페인과 통계 방법의 용도입니다 — 하지만 여기서의 비교(같은 검증된 문제, 같은 정지 기준, 같은 파생 시드)는 정확히 더 큰 증거가 구축되는 방식이며, 단일 실행은 정확히 그것이 아닙니다.
3️⃣ 솔버 메타데이터 읽기
각 등록된 솔버는 공개 계약으로 메타데이터를 지닙니다: 지원 목적, 능력 태그, 확률성, 기본 정지
기준, 그리고 정준 인용. 이를 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))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이 메타데이터는 registry.select가 필터링하는 대상이며 솔버 추천기가
설명하는 출처입니다. 완전한 레지스트리 — 베이스라인, 메타휴리스틱, 정확 어댑터, 그리고 NDSO
패밀리 — 는 알고리즘과 솔버 시스템에 카탈로그됩니다.
🧪 Tutorial 2: 작은 캠페인을 실행하고 그 결과를 읽기
캠페인은 구성된 실행의 집합 — 벤치마크 인스턴스를 솔버 및 목적과 교차한 것 — 으로, 명시적 시드,
예산, 체크포인트, 그리고 디스크-상 결과 저장소로 실행됩니다. 이 튜토리얼은
experiments/configs/smoke-pilot.json에서 추적되는 레시피와 같은 형태를 실행합니다: 두 스모크
인스턴스, 두 결정론적 베이스라인, 한 목적.
1️⃣ 캠페인 구성 및 실행
이를 first_campaign.py로 저장하세요. 캠페인을 선언하고, 결정론적 계획으로 검증하고, 드라이런으로
그 비용을 추정한 다음, 로컬 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)}")uv run python first_campaign.py로 실행:
planned runs: 4
estimated wall time: 2.0s
completed runs: 4
failed attempts: 0네 실행은 정확히 교차곱입니다: 2 벤치마크 인스턴스 × 2 솔버 × 1 목적, 두 솔버 모두 결정론적
이므로 셀당 한 실행. 각 실행의 시드는 root_seed와 실행의 위치로부터 파생되므로, 스크립트
재실행은 같은 레코드를 재현합니다; 체크포인트는 중단된 캠페인이 완료된 작업을 반복하지 않고
재개하게 합니다.
2️⃣ 디스크에 무엇이 떨어졌는지 검사하기
runner는 추적되는 실험 워크스페이스와 같은 레이아웃의 워크스페이스를 썼습니다:
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실행당 하나의 JSON 레코드, 캠페인·솔버·벤치마크·복제 인덱스로 주소 지정 — 경로 자체가
인덱스입니다. 각 레코드는 그 결정론적 페이로드 위에서 내용-해시되며, 그것이 replay 모드가
검증하는 대상입니다.
3️⃣ 분석을 위해 결과 로드하기
dispatchatlas.analytica는 캠페인 런타임을 임포트하지 않고 완료된 캠페인 디렉터리를 읽습니다.
이를 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}"
)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은 솔버와 목적별 기술 통계를 계산합니다. 솔버당 단 두 실행으로는 추론 방법
(유의성 검정, 신뢰 구간)이 저-검정력 결과를 산출하는 대신 제한 표면으로 라우팅됩니다 — 각 확률적
솔버-인스턴스 셀당 30회 독립 실행이라는 통계-검정력 하한은 분석 익스포트에
기술됩니다.
4️⃣ 증거 번들 익스포트 (선택)
같은 캠페인 디렉터리가 익스포트 명령에 공급되어, 표·그림·보충자료로 구성된 공개-필터링 증거 번들을 씁니다:
uv run dispatchatlas export `
--campaign-dir .\my-campaigns\results\first-campaign `
--target-dir .\exports\first-campaign `
--authorized-output-root .\exports `
--tier core번들은 exports/first-campaign/evidence-bundles/first-campaign-core/에 떨어집니다.
증거 번들 페이지가 네 등급과 번들 내용을 설명합니다.