Skip to content

Illustrate prescriptive sensitivity and conflict analysis in templates#78

Open
chriscoey wants to merge 10 commits into
mainfrom
prescriptive-sensitivity-conflict-examples
Open

Illustrate prescriptive sensitivity and conflict analysis in templates#78
chriscoey wants to merge 10 commits into
mainfrom
prescriptive-sensitivity-conflict-examples

Conversation

@chriscoey
Copy link
Copy Markdown
Member

@chriscoey chriscoey commented Jun 2, 2026

What

Extends three existing prescriptive-optimization templates to demonstrate the new sensitivity (LP marginals) and conflict / IIS (infeasibility diagnosis) analysis on solve():

  • factory_production — a maximize-profit product-mix LP. One solve(sensitivity=True) reads each factory's capacity shadow price and each product's reduced cost + basis status, joined back to its entity by key. A binding factory vs. a slack one shows the zero/nonzero shadow-price contrast, and the maximize objective mirrors the sign conventions of the minimize example below.
  • supplier_reliability — a minimize-cost sourcing LP. Reads supplier-capacity and product-demand shadow prices plus supply-lane reduced costs / basis status, then re-solves supplier-disruption scenarios.
  • cicd_runner_allocation — a binary assignment MIP. When a maintenance outage makes the schedule infeasible, solve(conflict=True) returns the conflict set (IIS): the stranded jobs and the binding runner cap, read back by entity key.

Each marginal or conflict joins to its grounding entity by key through the constraint's declared back-pointer (keyed_by={...} on satisfy), mirroring the automatic variable back-pointers. Each README walks through the model, the marginals/conflict, and how to act on them. All three runners were validated end-to-end against the solver, including assertion-level checks on objectives, marginal signs, basis statuses, and IIS membership.

Merge gating

These examples exercise the sensitivity and conflict APIs added in the upcoming PyRel release (RelationalAI/PyRel#1617), so the runners only work against a build that includes that API. Before merge, once that release ships: raise each template's relationalai dependency floor to the first version that includes sensitivity/conflict (the pins still say 1.0.14, which predates the API), and re-run the three templates against the released build.

🤖 Generated with Claude Code

chriscoey and others added 2 commits June 2, 2026 14:26
Extend three prescriptive-optimization templates to demonstrate the new
sensitivity (LP marginals) and conflict (IIS) analysis available on solve():

- factory_production: a maximize-profit product-mix LP that reads capacity
  shadow prices and product reduced costs / basis status from a single solve.
- supplier_reliability: a minimize-cost sourcing LP with capacity and demand
  shadow prices, lane reduced costs, plus supplier-disruption scenarios.
- cicd_runner_allocation: a binary assignment MIP that diagnoses an infeasible
  maintenance outage via conflict (IIS) membership.

Each marginal or conflict joins back to its grounding entity by key through
constraint back-pointers. Validated end-to-end against the solver.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ispatch, sharper marginals prose

- Aliased + sorted marginal and conflict tables so each README's expected-output
  matches actual stdout deterministically (baseline and scenario displays)
- Dispatch on conflict_status (read the IIS only for CONFLICT_FOUND) instead of
  asserting a single value, with a clear reason on other outcomes
- Correct the degenerate-breakpoint and one-way shadow-price wording; add a
  product-name uniqueness guard and tighten the plan tolerance
- Silence the benign rules-in-a-loop warning from the scenario sweep, by message

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 3, 2026

The docs preview for this pull request has been deployed to Vercel!

✅ Preview: https://relationalai-docs-2qo3wu73y-relationalai.vercel.app/build/templates
🔍 Inspect: https://vercel.com/relationalai/relationalai-docs/68uj46bvkNyfPxWmQ48oJ1U2kMk1

chriscoey and others added 8 commits June 3, 2026 23:45
The constraint back-pointer that joins a marginal or conflict membership to
its entity's data is now declared explicitly via satisfy(keyed_by={...})
rather than detected automatically. Declare the keys in all three templates
and align the docstring/README wording. Variable back-pointers are unchanged
(still derived from field names).

Validated end-to-end: supplier_reliability and factory_production return the
documented optima and marginals; cicd_runner_allocation returns CONFLICT_FOUND
with the documented IIS (six stranded high-CPU jobs + the ubuntu-xlarge cap).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The expected-output header claimed the conflict diagnosis is stable, but
which six of the seven stranded jobs the IIS names is solver-dependent
(observed across runs); only the statuses, costs, and binding cap are
stable.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The rules-created-in-a-loop false positive arises only while
solve_allocation rebuilds the Problem per scenario, so suppress it with
warnings.catch_warnings() inside that builder instead of mutating
process-wide warning state at module scope. Warning behavior everywhere
else in the run is now untouched.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The two min_cpu=8 jobs are compatible with only ubuntu-xlarge and
self-hosted-linux, so state the high-CPU compatibility claim as a bound
rather than implying all seven jobs match all three big Linux runners.
Restate the where= comment accurately: solve_for treats an empty where=
and None identically. Note in the README why the template's else branch
raises where the copyable snippet prints.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Regenerate v1/README.md to pick up the rewritten template descriptions;
extend cicd_runner_allocation's description and experience level to cover
the conflict-analysis addition. Add explanatory messages to the bare
objective asserts so a data edit fails with expected-vs-got instead of a
bare AssertionError, and drop a stray internal reference from a comment.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The maintenance-outage logic hard-codes the two offline runners and the
surviving ubuntu-xlarge cap; if runners.csv renames any of them the
where= exclusion silently excludes nothing and the outage stays
feasible, failing later with an unrelated message. Mirror the existing
workflow-side drift guard for the runner side, and note when the
capacity-shadow-price requires get validated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Note why the complementary-slackness frame keeps the supplier column
(select returns distinct rows, so an identifying column preserves one
row per lane), why the baseline order quantities are not pinned
(cost-equal alternate optima), and which Allocation fields serve the
feasible vs infeasible read paths.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
State the practical reason for the supplier column (identifiable rows,
names the offender on failure) without asserting projection semantics
that differ across backends.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant