Skip to main content

Project scheduling and earned value control for Python: CPM, PERT with Monte Carlo schedule risk, minimum-cost crashing, EVM and earned schedule, validated against published reference values.

Project description

pmcontrols

CI License: MIT

Project scheduling and earned value control for Python.

CPM, PERT with Monte Carlo schedule risk, minimum-cost crashing, and EVM/earned-schedule control — computed from the defining formulations, never from spreadsheet conventions, and checked against published reference values in the test suite.

Companion to lotsampling (acceptance sampling): lotsampling judges the lot, pmcontrols keeps the project honest.

Motivation

Every project office computes CPI and SPI; almost all of it happens in Excel. R and commercial tools (Primavera, Deltek, @RISK) cover schedule risk and earned value; in Python the landscape is a 4 KB CPM toy and an abandoned ERP add-on. There is no maintained library a cost engineer or a project-controls researcher can pip install to get:

  • the critical path with full ES/EF/LS/LF/slack accounting
  • PERT three-point analysis plus what the textbook procedure cannot give you: a Monte Carlo completion distribution and per-activity criticality indices
  • crashing as optimization — the cheapest set of compressions meeting a deadline, solved as the classical time/cost trade-off LP rather than by manual marginal-cost inspection
  • EVM with earned schedule — the full indicator set (CV, SV, CPI, SPI, the EAC family, TCPI, VAC) plus Lipke's time-based ES, SPI(t) and duration forecast IEAC(t), which plain EVM gets wrong late in projects

Quickstart

import pmcontrols as pm

activities = [
    {"id": "A", "predecessors": [],         "duration": 2},
    {"id": "B", "predecessors": [],         "duration": 3},
    {"id": "C", "predecessors": ["A"],      "duration": 2},
    {"id": "D", "predecessors": ["B"],      "duration": 4},
    {"id": "E", "predecessors": ["C"],      "duration": 4},
    {"id": "F", "predecessors": ["C"],      "duration": 3},
    {"id": "G", "predecessors": ["D", "E"], "duration": 5},
    {"id": "H", "predecessors": ["F", "G"], "duration": 2},
]

r = pm.cpm(activities)
r.stats["project_duration"]        # 15.0
r.meta["critical_activities"]      # ['A', 'C', 'E', 'G', 'H']
r.table                            # tidy ES/EF/LS/LF/slack DataFrame

# Cheapest way to finish in 13 periods (linear program):
r = pm.crash(crash_activities, target=13)
r.stats["total_crash_cost"]        # optimal, not greedy

# Plan once, freeze, control forever:
pm.plan(periods, pv_curve).save("pmb.json")     # commit this to git
r = pm.evm("pmb.json", ev=30_000, ac=35_000, at=4)
r.ok                 # False — CPI and SPI(t) below threshold
print(r.summary())   # audit text with plain-language verdict
r.stats["ieac_t"]    # earned-schedule duration forecast

r.ok is the automation primitive: a weekly cron job can evaluate the latest actuals against the frozen PMB and exit nonzero the moment cost or schedule efficiency breaches a threshold.

Validation philosophy

Every release must reproduce, in tests/validation_cases.json (each case ships with its full derivation):

  1. the General Foundry reference network — complete ES/EF/LS/LF/slack table, 15-period critical path, and optimal crash costs to 14 and 13 periods,
  2. hand-derived EVM/earned-schedule cases covering the full indicator set and the ES interpolation formula,
  3. identity and property checks (slack = LS−ES = LF−EF; SPI(t) = ES/AT; crash cost monotone in target; Monte Carlo means converging to analytic values),
  4. (before 0.1) published PMI/Lipke earned-schedule case studies, verified privately where copyright prevents redistribution.

Status

0.1.0 — first public release. The API surface is small on purpose; the Result/PMB contract is frozen and append-only from this version on.

Roadmap

Version Scope
0.2 Published PMI/Lipke earned-schedule case-study validation; Gantt and OC plotting (separate from the statistics)
0.3 Resource leveling and constrained scheduling; schedule risk drivers (correlation, risk events); EVM from time-phased ledgers (DataFrame in, indicators out)
0.4 Critical chain buffers; probabilistic crashing (crash under uncertainty); ES forecasting variants (performance factors); JOSS paper

Out of scope: Gantt-chart project editors (use dedicated PM tools), process control, acceptance sampling (see lotsampling), generic LP modeling (use scipy/pyomo directly).

License

MIT. Written and maintained by Atakan Arikan, MSc Student at Tsinghua University and Politecnico di Milano.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pmcontrols-0.1.0.tar.gz (17.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pmcontrols-0.1.0-py3-none-any.whl (14.8 kB view details)

Uploaded Python 3

File details

Details for the file pmcontrols-0.1.0.tar.gz.

File metadata

  • Download URL: pmcontrols-0.1.0.tar.gz
  • Upload date:
  • Size: 17.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for pmcontrols-0.1.0.tar.gz
Algorithm Hash digest
SHA256 86d539702fed7420bfe24123a91de7051d9830109469651b489f5d4765c65fb0
MD5 e26991615df19412bb3dfd3bd8929849
BLAKE2b-256 c38664198a9fb0f74f09bc6764db511e45d33f6d1ede5916ffb398da998213e2

See more details on using hashes here.

Provenance

The following attestation bundles were made for pmcontrols-0.1.0.tar.gz:

Publisher: release.yml on arikanatakan/pmcontrols

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pmcontrols-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: pmcontrols-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 14.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for pmcontrols-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f61302da7e6a697f4b84991e097db6a571beab4cd1f8dd091bda634afb6064fa
MD5 cdb333b11fa8b05bd34b787ebdd69049
BLAKE2b-256 79e752c90506c694e497cb8bd50eb139e53c8544ef74afdd7ac281abcc9d85d9

See more details on using hashes here.

Provenance

The following attestation bundles were made for pmcontrols-0.1.0-py3-none-any.whl:

Publisher: release.yml on arikanatakan/pmcontrols

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page