diff --git a/docs/source/conf.py b/docs/source/conf.py index 6228b139..342bcf32 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -34,11 +34,13 @@ # extensions = ['sphinx.ext.duration', 'sphinx.ext.autodoc', 'sphinx.ext.autosummary', 'sphinx.ext.doctest', # 'sphinx.ext.todo', 'sphinx.ext.coverage', 'sphinx.ext.ifconfig'] -extensions = ['autoapi.extension' +extensions = [ + 'autoapi.extension', + 'myst_parser' ] # todo_include_todos = True -source_suffix = '.rst' +source_suffix = {'.rst': 'restructuredtext', '.md': 'markdown'} master_doc = 'index' add_function_parentheses = True diff --git a/docs/source/eng_guidebook/algorithms.md b/docs/source/eng_guidebook/algorithms.md new file mode 100644 index 00000000..579014b7 --- /dev/null +++ b/docs/source/eng_guidebook/algorithms.md @@ -0,0 +1,139 @@ +# Scheduling Algorithms + +## How to choose an algorithm + +### Heuristic schedulers (HEFT, HEFTBetween, Topological) + +- Provide a workable schedule quickly. +- HEFT/HEFTBetween compute task order and approximate execution times to reduce project makespan. +- Topological orders tasks by dependencies without complex optimization. +- HEFT builds a plan from scratch over the entire graph, while HEFTBetween inserts new activities into an already + occupied calendar, trying not to reshuffle the previously built plan. + +Imports: + +```python +from sampo.scheduler.heft import HEFTScheduler +from sampo.scheduler.heft import HEFTBetweenScheduler +from sampo.scheduler.topological import TopologicalScheduler +``` + +--- + +### Genetic scheduler + +- Tries many different combinations and often finds a schedule with a shorter project completion time (minimizing project makespan). + Works slower than simpler algorithms. +- Key parameters: + - `number_of_generation` — how many times to improve the solutions (more → higher chance of improvement, but slower). + - `size_of_population` — how many alternatives to keep simultaneously (more → more ideas, but slower and more memory-consuming). + - `mutate_order` — how often to change the task order (while preserving dependencies) + (higher values → wider search, but slower convergence). + - `mutate_resources` — how often to change the allocation of resources/contractors + (higher values → better parallelism, but may cause more “conflicts” if resources are scarce). + - Additionally: `work_estimator`, `seed` (for reproducibility). + +Example: + +```python +from sampo.scheduler.genetic import GeneticScheduler + +scheduler = GeneticScheduler( + number_of_generation=50, + size_of_population=100, + mutate_order=0.1, + mutate_resources=0.1 +) +``` + +--- + +## Multi-Agent Scheduling + +Splits a project into parts (blocks), schedules them using different strategies, and assembles a global plan. +Useful for large projects and for combining strategies (`sampo.scheduler.multi_agency`). + +### “Auction” without block partitioning + +```python +from uuid import uuid4 +from sampo.generator.base import SimpleSynthetic +from sampo.scheduler.heft import HEFTScheduler +from sampo.scheduler.topological import TopologicalScheduler +from sampo.scheduler.multi_agency.multi_agency import Agent, StochasticManager +from sampo.schemas.contractor import Contractor +from sampo.schemas.resources import Worker +from sampo.generator.environment.contractor_by_wg import get_contractor_by_wg, ContractorGenerationMethod + +# 1) Small work graph +ss = SimpleSynthetic(231) +wg = ss.work_graph(bottom_border=30, top_border=40) + +# 2) Contractor with the required worker types +kinds = {req.kind for node in wg.nodes for req in node.work_unit.worker_reqs} +cid = str(uuid4()) +workers = {k: Worker(str(uuid4()), k, 50, contractor_id=cid) for k in kinds} +contractors = [get_contractor_by_wg( + wg, + scaler=1.0, # increase if needed, e.g., 1.2 or 1.5 + method=ContractorGenerationMethod.AVG, +)] + +# 3) Two agents with different approaches +agents = [ + Agent("HEFT", HEFTScheduler(), contractors), + Agent("Topological", TopologicalScheduler(), contractors), +] +manager = StochasticManager(agents) + +# 4) “Auction”: agents propose schedules; pick the best by finish time +start, end, schedule, winner = manager.run_auction(wg) +print("Winning agent:", winner.name, "Makespan:", end - start) +``` + +### With Block Partitioning + +```python +from random import Random +from sampo.generator.base import SimpleSynthetic +from sampo.scheduler.heft import HEFTScheduler +from sampo.scheduler.topological import TopologicalScheduler +from sampo.scheduler.multi_agency.multi_agency import Agent, StochasticManager +from sampo.scheduler.multi_agency.block_generator import generate_blocks, SyntheticBlockGraphType + +# 1) Build a "block graph" (each block is its own small WorkGraph) +seed = 231 +rand = Random(seed) +bg = generate_blocks( + SyntheticBlockGraphType.RANDOM, + n_blocks=4, + type_prop=[1, 1, 1], + count_supplier=lambda i: (10, 15), + edge_prob=0.3, + rand=rand +) + +# 2) Contractors for agents +ss = SimpleSynthetic(rand) +contractor_a = ss.contractor(40) +contractor_b = ss.contractor(40) + +# 3) Agents with different algorithms +agents = [ + Agent("HEFT", HEFTScheduler(), [contractor_a]), + Agent("Topo", TopologicalScheduler(), [contractor_b]), +] +manager = StochasticManager(agents) + +# 4) Schedule blocks in order, respecting inter-block dependencies +scheduled_blocks = manager.manage_blocks(bg) + +# 5) Summary: who took which block and when it ran +print("Scheduled blocks:") +for block_id, sblock in scheduled_blocks.items(): + print(f"Block {block_id}: agent={sblock.agent.name}, " + f"start={sblock.start_time}, end={sblock.end_time}, duration={sblock.duration}") + +project_finish = max(sb.end_time for sb in scheduled_blocks.values()) +print("Project finish time:", project_finish) +``` diff --git a/docs/source/eng_guidebook/connections.md b/docs/source/eng_guidebook/connections.md new file mode 100644 index 00000000..f59cb8ce --- /dev/null +++ b/docs/source/eng_guidebook/connections.md @@ -0,0 +1,75 @@ +# Task Dependencies + +## Terms + +- **Dependency** — an arrow between tasks that defines when the next one can start. +- **Lag** — the amount of time that must pass after one task before starting the next. +- **IFS (Interruption-Free Sequence)** — a sequence of consecutive tasks performed without breaks by the same workers. + +> **Why it matters (IFS):** It models a continuous block of work, ensuring that tasks performed by the same workers +> follow +> one another without any interruptions or delays. This is crucial for processes where stopping between steps is +> technologically undesirable or inefficient. + +--- + +## Dependency Types + +| Type | How to read | Meaning (short) | +|------|----------------------------|-----------------------------------------------------------------| +| FS | Finish → Start | B can start after A finishes (+ lag, if any) | +| FFS | Finish → Start (with lag) | Same as FS, but with a mandatory pause | +| IFS | Continuous: Finish → Start | B starts immediately after A with no break, by the same workers | +| SS | Start ↔ Start | A and B can start together | +| FF | Finish ↔ Finish | B must finish no earlier than A | + +## When to Use Each Type + +- Regular sequence of actions: **FS**. +- Technological pause required: **FFS** (or **FS** with a lag). +- Continuous work by the same workers without interruption: **IFS**. +- Simultaneous start of tasks: **SS**. +- Tasks must finish at the same time: **FF**. + +--- + +## Mini-Examples + +1) **FS + lag** + A: “Pour concrete” (finishes on Day 2) → lag 3 days → B: “Wall masonry” (not earlier than Day 5). + +2) **IFS** + A: “Drilling” ⇒ B: “Anchoring” ⇒ C: “Post installation” (same workers, no breaks). + +3) **SS** + A: “Server startup” ≡ B: “Monitoring launch” (simultaneous start). + +4) **FF** + A: “Main configuration” || B: “Documentation” (must finish at the same time). + +5) **FFS** + A: “Apply primer” → lag 4 hours → B: “Painting”. + +Legend: → (FS/FFS), ⇒ (IFS), ≡ (SS), || (FF). + +--- + +## Example of a CSV File with Dependencies + +Suppose we have a file named `predecessors.csv`: + +``` +child_id,parent_id,type,lag +B,A,FS,3 +C,B,IFS,0 +D,C,IFS,0 +E,A,SS,0 +``` + +Explanation: + +- **B** starts after **A** + 3 (lag of 3 days). +- **C** and **D** together with **B** form a continuous chain (**IFS**). +- **E** starts together with **A** (**SS**, does not delay the process). + +``` \ No newline at end of file diff --git a/docs/source/eng_guidebook/contractors.md b/docs/source/eng_guidebook/contractors.md new file mode 100644 index 00000000..dfd53770 --- /dev/null +++ b/docs/source/eng_guidebook/contractors.md @@ -0,0 +1,127 @@ +# Contractor + +## Terms + +- **Worker Requirement (`WorkerReq`)** — defines who and how many people are needed for a task: + profession (`kind`), minimum/maximum number of workers (`min_count…max_count`), and work volume or productivity rate ( + `volume`). +- **Worker** — represents human resources: specialization (`name`), quantity (`count`), productivity (`productivity`), + owner (`contractor_id`), and optionally cost per unit (`cost_one_unit`). +- **Equipment** — a non-human resource: its type and quantity. Tasks use it the same way as workers. +- **Contractor** — a resource provider, essentially a dictionary of available workers and equipment for the scheduler. + +--- + +## Available Professions: + +- 'driver' +- 'fitter' +- 'handyman' +- 'electrician' +- 'manager' +- 'engineer' + +## How to Define a Contractor + +### Manually + +```python +from sampo.schemas.contractor import Contractor +from sampo.schemas.resources import Worker +from sampo.schemas.interval import IntervalGaussian + +# Example: a contractor with two professions (drivers and fitters) +contractor = Contractor( + workers={ + # dictionary key 'driver' must match Worker.name='driver' + 'driver': Worker( + id='w1', + name='driver', # profession (must match WorkerReq.kind) + count=8, # number of available workers + productivity=IntervalGaussian(1.0, 0.1, 0.5, 1.5) # average productivity with deviation + # cost_one_unit=... optional: cost per unit if cost calculation is required + # contractor_id='c1' usually matches Contractor.id (if set manually) + ), + 'fitter': Worker( + id='w2', + name='fitter', + count=6, + productivity=IntervalGaussian(1.2, 0.1, 0.8, 1.6) + ), + }, + id='c1', + name='Contractor A' +) +``` + +**Notes:** + +* Dictionary keys in `workers` **must match** each `Worker.name`. +* The field `WorkerReq.kind` from tasks must match `Worker.name`; otherwise, the scheduler cannot assign workers. +* The `contractor_id` of each worker usually matches `Contractor.id`. +* `IntervalGaussian(μ, σ, low, high)` — defines **average productivity (μ)** with standard deviation (σ) and range + limits `low…high`. + +### Quick resource package generator + +```python +from sampo.generator.base import SimpleSynthetic + +ss = SimpleSynthetic() +contractor = ss.contractor(pack_worker_count=10) +# pack_worker_count: A scaling factor for the number of workers in each profession +``` + +--- + +### Contractor “from Graph” (based on task requirements) + +```python +from sampo.generator.environment.contractor_by_wg import get_contractor_by_wg, ContractorGenerationMethod + +# wg — your WorkGraph with tasks and their WorkerReq +contractor = get_contractor_by_wg( + wg, + scaler=1.0, # scale resource capacities (e.g., 1.5 = +50%) + method=ContractorGenerationMethod.AVG # aggregate requirements by average +) +``` + +**How it works:** + +* Analyzes all `WorkerReq` in the project. +* Aggregates or averages resource needs by job type. +* Builds a contractor with an appropriate number of workers per profession. +* The `scaler` parameter lets you quickly increase or decrease available resources without editing them manually. + +--- + +## A Few More Mini-Examples + +Two contractors defined separately: + +```python +from sampo.schemas.contractor import Contractor +from sampo.schemas.resources import Worker + +contractor_a = Contractor( + id='ca', name='Team A', + workers={'welder': Worker(id='wa', name='welder', count=4)} +) + +contractor_b = Contractor( + id='cb', name='Team B', + workers={'driver': Worker(id='wb', name='driver', count=6)} +) + +contractors = [contractor_a, contractor_b] +``` + +Quickly increase resources for an existing one: + +```python +# Previously there were 6 drivers; now there will be 10 +contractor.workers['driver'].count = 10 +``` + +--- \ No newline at end of file diff --git a/docs/source/eng_guidebook/index.md b/docs/source/eng_guidebook/index.md new file mode 100644 index 00000000..c3cc416b --- /dev/null +++ b/docs/source/eng_guidebook/index.md @@ -0,0 +1,14 @@ +# Guidebook + +```{toctree} +:maxdepth: 2 +:numbered: +caption: Guidebook SAMPO +intro +quickstart +work_graph +connections +contractors +algorithms +``` + diff --git a/docs/source/eng_guidebook/intro.md b/docs/source/eng_guidebook/intro.md new file mode 100644 index 00000000..6ef81102 --- /dev/null +++ b/docs/source/eng_guidebook/intro.md @@ -0,0 +1,33 @@ +# Introduction + +## Who is this guidebook for? + +The guidebook is structured to help users with different levels of experience: + +* Introductory level — what SAMPO is, how it can help, and how to get started quickly. +* Advanced level — how to customize SAMPO for your specific tasks. + +## What is SAMPO? + +**SAMPO** is a framework for automated optimization of business process planning. +It enables effective use of accumulated corporate knowledge and historical data to automatically build business +process schedules optimized for the required performance indicators. + +## Key Features and Advantages + +SAMPO is built on **metaheuristic, genetic, and neural-network-based scheduling algorithms** that analyze historical +production data and solve the **multi-criteria project scheduling optimization** problem while leveraging accumulated +experience. +A key feature of the framework is its ability to efficiently over **long-term** time horizons under +uncertainty and with incomplete historical data. + +Thanks to its **modular architecture**, SAMPO supports the integration of **domain-specific algorithms and models**. +This makes the framework applicable to **industrial scheduling problems** across various sectors, including +mining and manufacturing, construction, transportation, and energy. + +## Openness and Documentation + +Licensed under **BSD 3-Clause**, with detailed documentation and examples available in **Jupyter Notebooks**. + +> **BSD 3-Clause** is a permissive open-source license that permits the use, modification, and distribution of the code +> (including in commercial projects) as long as copyright notices and disclaimers of liability are retained. diff --git a/docs/source/eng_guidebook/quickstart.md b/docs/source/eng_guidebook/quickstart.md new file mode 100644 index 00000000..56b18cf8 --- /dev/null +++ b/docs/source/eng_guidebook/quickstart.md @@ -0,0 +1,168 @@ +# Quick Start + +This section shows how to install the package, prepare a simple example, run the scheduler, and view the result. + +## Installation + +SAMPO is available as a Python package (requires Python 3.10.x): + +```bash +pip install sampo +``` + +## First Plan in a Few Steps + +Let's create a simple project and define it step by step: + +1) **Work graph** — create a `WorkGraph`. For a quick start, we will generate a synthetic one. +2) **Resources** — define a list of `Contractor` objects with workers. +3) **Algorithm** — choose a `Scheduler` (heuristic or genetic). +4) **Run** — generate a `Schedule` and review the result. + + +--- + +### Create a WorkGraph (quick method — synthetic generator) + +```python +from sampo.generator.base import SimpleSynthetic +from sampo.generator.pipeline import SyntheticGraphType +from sampo.schemas.graph import WorkGraph + +# Initialize the synthetic generator +synthetic = SimpleSynthetic() + +# Generate a small graph: ~2 clusters with 5–8 tasks each +work_graph: WorkGraph = synthetic.work_graph( + mode=SyntheticGraphType.GENERAL, # structure type: GENERAL / PARALLEL / SEQUENTIAL + cluster_counts=2, # 2 clusters + bottom_border=5, # 5–8 tasks per cluster + top_border=8 +) +print(f"Generated a WorkGraph with {len(work_graph.nodes)} tasks.") +``` + +--- + +### Resources (Contractors) + +**Important:** the synthetic graph uses the following standard job types: +`driver`, `fitter`, `manager`, `handyman`, `electrician`, `engineer`. + +A contractor must include workers for every required job type. +The `workers` dictionary is keyed by the resource type name (`req.kind`). + +```python +from sampo.schemas.contractor import Contractor +from sampo.schemas.resources import Worker + +# Define several workers for each required type +workers = [ + Worker(id="w_driver", name="driver", count=20), + Worker(id="w_fitter", name="fitter", count=20), + Worker(id="w_manager", name="manager", count=10), + Worker(id="w_handyman", name="handyman", count=20), + Worker(id="w_electrician", name="electrician", count=10), + Worker(id="w_engineer", name="engineer", count=10), +] + +# A single contractor with a complete worker pool +contractors = [ + Contractor( + id="c1", + name="General Contractor", + # Keys are resource type names (match WorkerReq.kind) + workers={w.name: w for w in workers} + ) +] +``` + +Alternative: auto-generate a contractor “from the graph” to ensure resource coverage: + +```python +from sampo.generator.environment.contractor_by_wg import get_contractor_by_wg, ContractorGenerationMethod + +contractors = [get_contractor_by_wg( + work_graph, + scaler=1.0, # capacity multiplier (>= 1.0) + method=ContractorGenerationMethod.AVG, # average between min/max needs + contractor_id="c1", + contractor_name="General Contractor" +)] +``` + +--- + +### Choose a Scheduler + +```python +from sampo.scheduler.heft import HEFTScheduler + +# also available: +# from sampo.scheduler.topological import TopologicalScheduler +# from sampo.scheduler.genetic import GeneticScheduler + +scheduler = HEFTScheduler() # fast heuristic for a quick start +``` + +--- + +### Run the Scheduling + +The `schedule(...)` method returns a list of `Schedule` objects. +Take the first one (the best solution): + +```python +best_schedule = scheduler.schedule(work_graph, contractors)[0] +print(f"Projected project duration (makespan): {best_schedule.execution_time}") +``` + +If you need additional details (finish time, timeline, node order), use the extended method: + +```python +best_schedule, finish_time, timeline, node_order = scheduler.schedule_with_cache(work_graph, contractors)[0] +print(f"Makespan: {best_schedule.execution_time}") +``` + +--- + +### View the Schedule (Gantt Chart) + +A reliable way is to get an aggregated representation and visualize it: + +```python +from sampo.utilities.visualization import schedule_gant_chart_fig, VisualizationMode + +merged = best_schedule.merged_stages_datetime_df(offset='2025-01-01') + +fig = schedule_gant_chart_fig( + merged, + visualization=VisualizationMode.ReturnFig + # Specifies what to do with the figure (here: return the object so it can be shown) +) +fig.show() +``` + +- If you want to see only your tasks without the “internal” technical ones, use the table `best_schedule.pure_schedule_df`. +- For a Gantt chart, it is usually better to use the full calendar representation from `best_schedule.merged_stages_datetime_df`. + +--- + +### (Optional) SchedulingPipeline + +The same steps can be performed in a **fluent style** using the `SchedulingPipeline`. +The `finish()` method returns a list of `ScheduledProject`; take `[0]` and read its `project.schedule`. + + +```python +from sampo.pipeline import SchedulingPipeline +from sampo.scheduler.heft import HEFTScheduler + +project = (SchedulingPipeline.create() +.wg(work_graph) +.contractors(contractors) +.schedule(HEFTScheduler()) +.finish()[0]) + +print(f"Project duration: {project.schedule.execution_time}") +``` diff --git a/docs/source/eng_guidebook/work_graph.md b/docs/source/eng_guidebook/work_graph.md new file mode 100644 index 00000000..efa55a66 --- /dev/null +++ b/docs/source/eng_guidebook/work_graph.md @@ -0,0 +1,174 @@ +# WorkGraph + +## Terms + +- **WorkGraph** — a "project map" represented as a directed acyclic graph. Two service nodes — start and end — are added + automatically. +- **GraphNode** — a graph node that contains a task (`WorkUnit`) and links to its parent/child nodes (each link has a + type and a lag). +- **WorkUnit** — the description of a task: its volume and resource requirements (what kinds of workers and how many). + +--- + +## How to Create a WorkGraph + +### Generate Automatically (Quick Start) + +```python +from sampo.generator.base import SimpleSynthetic +from sampo.generator.pipeline import SyntheticGraphType + +ss = SimpleSynthetic() +wg = ss.work_graph( + mode=SyntheticGraphType.GENERAL, # structure type: General / Parallel / Sequential + cluster_counts=10, # number of clusters (groups of tasks) + bottom_border=100, # lower limit of the number of tasks + top_border=200 # upper limit of the number of tasks +) +``` + +* `mode` — the form of the graph (general, parallel, sequential). +* `cluster_counts` — how many groups of tasks the graph contains. +* `bottom_border` / `top_border` — the range for the number of tasks. + +--- + +### Load from CSV + +```python +from sampo.pipeline import SchedulingPipeline +from sampo.pipeline.lag_optimization import LagOptimizationStrategy +from sampo.scheduler.heft import HEFTScheduler + +project = ( + SchedulingPipeline.create() + .wg(wg='tests/parser/test_wg.csv', sep=';', all_connections=True) + .lag_optimize(LagOptimizationStrategy.TRUE) # AUTO / NONE / TRUE + .schedule(HEFTScheduler()) + .finish()[0] +) + +wg = project.wg # ready-to-use WorkGraph +schedule = project.schedule +``` + +* `all_connections=True` — try to reconstruct missing dependencies if they are absent in the input data. +* `sep=';'` — column separator in the CSV file. +* `LagOptimizationStrategy` — specifies how lags are processed (you can rely on the "AUTO" option to choose + automatically). + +> If you use `contractor` autogeneration through `get_contractor_by_wg`, **resource columns are optional** — +> only mandatory fields and dependencies are required. + +--- + +## CSV Structure + +### Required Columns + +| Field | Description | +|-----------------|---------------------------------------------------------------| +| `activity_id` | Unique identifier of the task | +| `activity_name` | Human-readable task name | +| `granular_name` | Short task code or label | +| `volume` | Work volume (numeric value) | +| `measurement` | Unit of measurement (e.g., `unit`, `m3`, `pcs`) | +| `priority` | Integer for prioritization (set to `0` for all if not needed) | + +### Dependencies + +Three synchronized lists (their lengths must match): + +* `predecessor_ids` — predecessor IDs separated by commas +* `connection_types` — connection types (FS, SS, FF, etc.) +* `lags` — time delays (numeric values) + +> An empty cell means **three consecutive separators with no spaces** (`;;;`). + +> Dependency example: +> `predecessor_ids="A,B"`, `connection_types="FS,SS"`, `lags="0,3"` + +### Resources (Optional) + +| Field | Format | +|--------------|-------------------------------------------------------| +| `min_req` | JSON dictionary of minimally required resources | +| `max_req` | JSON dictionary of maximum allowed resources | +| `req_volume` | JSON dictionary of norms/volumes for time calculation | + +* Use **valid JSON** with double quotes: + `{"welder": 2, "driver": 1}` +* If these columns are missing, the scheduler automatically generates resources (for example, using + `get_contractor_by_wg`). +* Keys must match `Worker.name`. + +--- + +### Minimal CSV (Without Resources) + +``` +activity_id;activity_name;granular_name;volume;measurement;priority;predecessor_ids;connection_types;lags +A;Task A;A;1.0;unit;0;;; +B;Task B;B;1.0;unit;0;A;FS;0 +C;Task C;C;1.0;unit;0;B;FS;0 +``` + +### CSV with Resources + +``` +activity_id;activity_name;granular_name;volume;measurement;priority;predecessor_ids;connection_types;lags;min_req;max_req;req_volume +A;Site prep;A;1.0;unit;0;;;;"{""driver"":1,""handyman"":1}";"{""driver"":2,""handyman"":2}";"{""driver"":8,""handyman"":8}" +B;Foundation;B;1.0;unit;0;A;FS;0;"{""fitter"":2,""engineer"":1}";"{""fitter"":4,""engineer"":2}";"{""fitter"":12,""engineer"":12}" +``` + +--- + +### Auto-generate a `Contractor` for a CSV-based `WorkGraph` + +```python +from sampo.generator.environment.contractor_by_wg import get_contractor_by_wg, ContractorGenerationMethod +from sampo.scheduler.heft import HEFTScheduler + +wg = project.wg + +contractors = [get_contractor_by_wg( + wg, + scaler=1.0, + method=ContractorGenerationMethod.AVG, + contractor_id="c_csv", + contractor_name="CSV Contractor" +)] + +scheduler = HEFTScheduler() +best_schedule, *_ = scheduler.schedule_with_cache(wg, contractors)[0] +print(f"Makespan: {best_schedule.execution_time}") +``` + +--- + +### Create a `WorkGraph` with Python + +```python +from sampo.schemas.works import WorkUnit +from sampo.schemas.graph import GraphNode, WorkGraph, EdgeType +from sampo.schemas.requirements import WorkerReq +from sampo.schemas.time import Time + +# Example chain: A -> B -> C (FS, zero lags) +wu_a = WorkUnit( + id='A', name='Task A', + worker_reqs=[WorkerReq(kind='driver', volume=Time(10), min_count=2, max_count=4)], + volume=1.0, is_service_unit=False +) +wu_b = WorkUnit(id='B', name='Task B', worker_reqs=[], volume=1.0, is_service_unit=False) +wu_c = WorkUnit(id='C', name='Task C', worker_reqs=[], volume=1.0, is_service_unit=False) + +n_a = GraphNode(wu_a, []) +n_b = GraphNode(wu_b, [(n_a, 0, EdgeType.FinishStart)]) # FS +n_c = GraphNode(wu_c, [(n_b, 0, EdgeType.FinishStart)]) # FS + +wg = WorkGraph.from_nodes([n_a, n_b, n_c]) +``` + +* Mandatory `WorkUnit` fields: `id`, `name`. +* For export, it is also useful to specify `volume`, `measurement`, `priority`. diff --git a/docs/source/index.rst b/docs/source/index.rst index f65a1dd0..68cbbec1 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -1,5 +1,5 @@ .. SAMPO documentation master file, created by - sphinx-quickstart on Sun Jul 2 18:31:48 2023. + sphinx-quickstart on Sun Jul 2 18:31:48 2025. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. @@ -7,13 +7,11 @@ Welcome to SAMPO's documentation! ================================= .. toctree:: - :maxdepth: 1 + :maxdepth: 2 :caption: Contents: - Install - Usage - Features - autoapi/index + eng_guidebook/index + autoapi/sampo/index Supported by diff --git a/requirements.txt b/requirements.txt index c39d5c7b..12c8e82d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -26,16 +26,16 @@ pytest-xdist~=3.1.0 # Sphinx version is pinned so that new versions that introduce new warnings # won't suddenly cause build failures. Updating the version is fine as long # as no warnings are raised by doing so. -sphinx>=4.5.0 +sphinx==7.4.7 blurb sphinx-lint==0.6.7 sphinxext-opengraph==0.7.5 -sphinx-autoapi==2.1.1 +sphinx-autoapi==3.1.0 +myst-parser==4.0.1 furo>=2023.5.20 # The theme used by the documentation is stored separately, so we need # to install that as well. python-docs-theme>=2022.1 sphinx-rtd-theme - - +astroid<4