Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
# cvx-workflow-skills

Portable [Agent Skills](https://agentskills.io/) for building optimization models,
describing them, and implementing them through existing solvers. Use them with
describing and debugging them, and implementing them through existing solvers. Use them with
Claude Code, Codex, OpenCode, or pi. Each assembled skill includes its own
instructions, references, examples, helpers, and license where applicable.

## Skills

| Skill | What it does |
|---|---|
| [cvx-model](skills/cvx-model/SKILL.md) | Turns natural-language requirements into reusable, efficient CVXPY code for real continuous convex LP, QP, and SOCP problems. |
| [cvx-model](skills/cvx-model/SKILL.md) | Turns natural-language requirements into reusable, efficient CVXPY code for real continuous convex LP, QP, and SOCP problems, with lightweight solver routing and requested dual multipliers. |
| [cvx-explain](skills/cvx-explain/SKILL.md) | Reads CVXPY code and produces a Markdown/LaTeX description of its variables, parameters, fixed data, objective, and constraints. |
| [cvx-debug](skills/cvx-debug/SKILL.md) | Diagnoses existing CVXPY models, proposes focused repairs, and checks modeling, implementation, or performance issues using available evidence. |
| [cvx-canon](skills/cvx-canon/SKILL.md) | Generates Moreau, SCS, HiGHS, or IPOPT implementations, including assembly, parameter updates, and original-variable recovery. Supports focused convex relaxations and convex-concave procedures. |

`cvx-model` keeps its modeling scope focused for use with smaller models.
`cvx-debug` loads references only for the reported issue; `cvx-explain` describes
the code as written. Requested dual multipliers are distinct from symbolic dual
derivation, which remains outside these skills' scope.
`cvx-canon` is intended for more capable models: it accounts for software
framework, hardware, precision, batching, and differentiation requirements.
Moreau IPM is its default convex conic backend, including PyTorch/JAX paths;
Expand All @@ -23,6 +27,9 @@ IPOPT supports CasADi, Pyomo, and native callbacks for local nonlinear optimizat

The skills are under active development. `cvx-model` has small-model application
evaluations and numerical checks; `cvx-explain` has offline description checks.
The new routing, multiplier, and quadratic-representation guidance has focused
local numerical checks; `cvx-debug` has not yet had live model or skill-selection
evaluations. Earlier modeling scores do not qualify these additions.
`cvx-canon` is experimental: CPU checks cover conic, MILP, derivative, CCP,
PyTorch/JAX batch-gradient, and CasADi/IPOPT examples. Its latest framework
additions have local checks; the model evaluation covered an earlier version.
Expand Down Expand Up @@ -74,6 +81,8 @@ For example, ask your agent:
parameters.”
- **cvx-explain:** “Describe this CVXPY model in Markdown, distinguishing decision
variables, parameters, and fixed data.”
- **cvx-debug:** “This CVXPY model fails DCP checks. Diagnose the cause and give
an equivalent correction, preserving the intended constraints.”
- **cvx-canon:** “Implement this optimization problem using Moreau in PyTorch,
on CPU with float64 data, batching, and gradients through the solution.”

Expand Down
44 changes: 44 additions & 0 deletions release.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,18 @@
{
"source": "skills/cvx-model/scripts/exact_atoms.py",
"target": "scripts/exact_atoms.py"
},
{
"source": "skills/cvx-model/references/multipliers.md",
"target": "references/multipliers.md"
},
{
"source": "skills/cvx-model/references/quadratics.md",
"target": "references/quadratics.md"
},
{
"source": "skills/cvx-model/references/solver-routing.md",
"target": "references/solver-routing.md"
}
]
},
Expand Down Expand Up @@ -192,6 +204,38 @@
"target": "scripts/cone_layout.py"
}
]
},
"cvx-debug": {
"files": [
{
"source": "LICENSE",
"target": "LICENSE"
},
{
"source": "skills/cvx-debug/SKILL.md",
"target": "SKILL.md"
},
{
"source": "skills/cvx-debug/references/implementation.md",
"target": "references/implementation.md"
},
{
"source": "skills/cvx-debug/references/modeling.md",
"target": "references/modeling.md"
},
{
"source": "skills/cvx-debug/references/performance.md",
"target": "references/performance.md"
},
{
"source": "skills/cvx-debug/references/quadratics.md",
"target": "references/quadratics.md"
},
{
"source": "skills/cvx-debug/references/solver-routing.md",
"target": "references/solver-routing.md"
}
]
}
}
}
63 changes: 63 additions & 0 deletions skills/cvx-debug/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
---
name: cvx-debug
description: Diagnose and repair supplied CVXPY code or formulations with modeling errors, DCP/DPP failures, incorrect results, infeasibility, or poor performance. Recommend suitable solvers using problem structure and evidence. Use for debugging existing models, not literal documentation, fresh code generation, symbolic dual derivation, or native/custom solver implementation.
license: Apache-2.0
---

# Diagnose an existing optimization model

Return evidence-backed findings and focused corrections, with checks performed
and remaining uncertainty. Keep this proportional to the reported symptom;
correct code may need no change. Literal descriptions belong to `cvx-explain`
and fresh CVXPY implementations to `cvx-model`; neither must be installed.

## Establish the issue

Read supplied source, formulation, data, and error/status evidence. Distinguish
the intended problem from what the code actually implements. Ask for missing
requirements only when they affect the diagnosis; code alone cannot establish
application intent. A runtime Problem may have lost original names and context.
Use the existing environment and supplied instance where practical. Report
unavailable evidence rather than inventing an error or timing.

Read only the references matching the symptom:

- Wrong formulation, unexpected results, infeasibility, or unboundedness:
[modeling and statuses](references/modeling.md).
- Shape, atom, DCP, DPP, or quadratic-expression failure:
[implementation](references/implementation.md); for quadratic terms read
[quadratic representations](references/quadratics.md).
- Slow construction, compilation, repeated solves, or numerical convergence:
[performance](references/performance.md).
- Solver choice or polyhedral feasibility structure:
[solver routing](references/solver-routing.md).

Separate a demonstrated bug, a suspected issue needing evidence, and an optional
improvement. Cite the relevant expression, data, exception, or measurement and
explain its consequence. Do not turn every diagnosis into a full model rewrite
or an automatic benchmark across solvers.

## Correct and verify

Give or apply a minimal repair within the requested scope. Preserve the original
objective, domains, constraints, and interface unless a change is explicitly
requested. Label a proposed modeling change as such. An indefinite quadratic,
nonconvex equality, or unsupported cone is not repaired by dropping requirements,
asserting PSD, adding arbitrary bounds, or silently introducing a relaxation.

Verify three questions separately: does the code match the stated requirements;
is the replacement equivalent under its assumptions; and do numerical results
meet original-domain checks? DCP acceptance or solver success proves neither
of the first two. Reproduce the reported failure and check the repair when
execution is available, using meaningful original-expression/residual checks.
For a performance claim, compare at matched accuracy and state timing boundaries.

Diagnosis can cover expressions beyond continuous LP/QP/SOCP, including an affine
operator on a matrix variable, without promising a general implementation of
unsupported problem classes. Explain any scope obstruction. Solver-native code,
custom algorithms, and symbolic dual derivation are separate deliverables.

Return the issue and consequence first, then the correction and actual validation.
If the model is correct or evidence is insufficient, say so and identify a useful
next check. Do not claim certification, speedups, or solved problems without
the corresponding evidence.
43 changes: 43 additions & 0 deletions skills/cvx-debug/references/implementation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Implementation diagnosis

## Shapes before curvature

Inspect `.shape`, variable/parameter definitions, reduction axes, and operands.
An (m,) vector and an (m,1) column can broadcast into an unintended (m,m)
expression. Check `@` versus `cp.multiply`, row/column indexing, and explicit
reshape order. Preserve sparse data; `np.asarray` is not a sparse conversion.
Use CVXPY atoms rather than NumPy functions on symbolic expressions.

## DCP failure

Locate the first failed composition using subexpression `.sign`, `.curvature`,
and `.shape`. Check objective direction, inequality orientation, affine
equalities, and parameter domains. Mathematical convexity and DCP acceptance
are different: `sqrt(1 + square(x))` is exactly `norm(hstack([1, x]), 2)`.
An exact atom/reformulation can fix representation without changing the model.
Explicit sign constraints need not inform DCP analysis; suitable attributes or
known-sign expressions can, but never invent a domain solely to pass analysis.

Read [quadratic representations](quadratics.md) for `quad_form` failures. First
identify which argument varies: a variable vector with PSD data admits a factor
form; a fixed vector with a matrix variable gives an affine trace operator.
Check the replacement against the original expression, not only `is_dcp()`.
Do not treat all quadratic-form failures as one numerical bug.

## DPP and reuse

Check whether changing data is actually `cp.Parameter` data, whether the Problem
is built once, and whether `problem.is_dcp(dpp=True)` holds on the concrete path.
Products of parameters can be DCP but not DPP. A PSD matrix Parameter in
`quad_form` can fail DPP; an externally computed factor Parameter in
`sum_squares(R @ x)` can help. Preserve factor orientation and update validation.
Factoring costs, changing rank/shapes, and solver refactorization still matter.

Keep fixed builder inputs distinct from Parameters. Invalid input, infeasible
model, unavailable solver, DCP failure, and numerical failure are different
outcomes. A correct model can be infeasible; do not make input validation reject
instances just because their constraints have no feasible point.

Sources: [CVXPY DCP](https://www.cvxpy.org/tutorial/dcp/index.html),
[DPP](https://www.cvxpy.org/tutorial/dpp/index.html),
[constraints](https://www.cvxpy.org/tutorial/constraints/index.html).
55 changes: 55 additions & 0 deletions skills/cvx-debug/references/modeling.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Requirements, results, and statuses

Compare supplied intent with implemented variables, domains, units, objective
direction/factors/constants, and each constraint. Look for a budget equality
versus cap, reversed demand, omitted bounds, borrowing assumptions, missing
conservation, or loss normalization. A sum of absolute residuals differs from
the absolute value of their sum. These are errors only relative to the intended
problem; do not invent missing application meaning.

Check data-dependent construction branches and implicit variable/atom domains.
Describe auxiliaries literally before proposing elimination. For a candidate
repair, account for every original requirement and label equivalence assumptions.
Do not infer equivalence from one matching optimum.

## Unexpected or incorrect results

Check status before using `.value`. Evaluate the original objective and constraint
residuals at the returned raw point with scale-aware tolerances; rounded printing
does not establish feasibility. Include implicit domains and transformation
recovery. A DCP model with a successful solve can still implement the wrong task.
For nonunique optima, compare objective and applicable optimality conditions rather
than insisting on a particular solution vector.

## Infeasible or unbounded

Check actual data for conflicting bounds, inconsistent conservation, unit
mismatches, absent constraints, and objective signs. Substitute a supplied known
feasible point directly. An empty interval lower>upper proves infeasibility; min
-c*x with x>=0 and c>0 has an improving ray. Give the concrete argument when one
exists. Adding arbitrary bounds or dropping constraints changes the problem.

For an ambiguous infeasible-or-unbounded status, a diagnostic feasibility solve
can use the same constraints and zero objective, or compare a compatible solver.
Label it as a diagnostic problem. Preserve domains implicit in the original
objective when removing that objective; otherwise even the feasible set changes.
A numerically uncertain feasibility result does not resolve the ambiguity.
Solver statuses alone are not independently checked certificates.

## Multipliers and accuracy

Missing `.dual_value` can follow from failed solves or attributes instead of
explicit constraints. Duplicate restrictions can split multipliers. Check row
indexing, inequality signs, objective/row scaling, and missing/nonfinite values
before interpreting them. Returned duals alone prove neither strong duality nor
an optimality certificate. Symbolic dual derivation is out of scope.
Some versions expose dual rays/certificate arrays after infeasible solves; check
status even when arrays are present and never interpret them as optimal multipliers.

Treat `optimal_inaccurate`, iteration limits, and invalid data separately. Check
original residuals, coefficient ranges, application units, and solver settings.
Changing scaling needs consistent primal recovery; do not delete a difficult row
or silently alter data. A request for more decimals is not evidence of accuracy.

Sources: [CVXPY problems](https://www.cvxpy.org/tutorial/intro/index.html),
[dual variables](https://www.cvxpy.org/tutorial/advanced/index.html#dual-variables).
39 changes: 39 additions & 0 deletions skills/cvx-debug/references/performance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Locate the cost before changing the model

Use the supplied workload and separate construction, first compilation/setup,
parameter updates, solve-call wall time, and reported solver time. Some solver
statistics omit costs or use different boundaries. Distinguish one-shot latency
from repeated throughput. State unavailable measurements; a large problem alone
does not establish the bottleneck.

- Construction/compilation: inspect scalar loops, accidental broadcasting,
dense identities/Gram matrices, unnecessary auxiliaries, and lost sparsity.
Vectorization should preserve axes and the original constraints.
- Repeated solves: build once when structure is fixed, use Parameters for changing
data, and check DPP. Compilation caching, warm starts, symbolic factorization,
and numerical factorization reuse are distinct. Matrix changes can invalidate
numerical reuse even when compilation is cached.
- Solver work: read [solver routing](solver-routing.md); inspect representation,
conditioning, residuals, accuracy settings, and sparsity/fill-in. Polyhedrality
is one signal, not proof that active-set methods win.

Bounds attributes can reduce explicit rows for particular interfaces, while
explicit constraints expose requested multipliers. Preserve dual requirements
when proposing that change. Fewer rows or a smaller cone do not by themselves
prove lower runtime. Read [quadratic representations](quadratics.md) before
changing a quadratic term; include factor/operator assembly and update costs.

Offer one justified improvement or a small comparison proportional to the issue.
Keep data, settings, versions, and timing boundaries reproducible, and compare
original-domain residuals and objective accuracy. Do not describe default
solver settings as equivalent accuracy across backends. If execution or relevant
hardware is unavailable, give a hypothesis and measurement plan, not a speedup.

Native deployment (`cvx-canon`) may help when modeling overhead is consequential;
it is not an automatic remedy for slow numerical convergence. Custom algorithm
implementation requires a separate request and evidence that existing interfaces
cannot meet the workload. These boundaries do not require sibling skills to be
installed.

Sources: [CVXPY solver features](https://www.cvxpy.org/tutorial/solvers/index.html),
[DPP](https://www.cvxpy.org/tutorial/dpp/index.html).
63 changes: 63 additions & 0 deletions skills/cvx-debug/references/quadratics.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Quadratic expressions: identify what varies

These patterns cover real-valued expressions. Preserve objective factors,
constants, dimensions, and domains. An equivalent expression can have different
compilation and solve costs; measure before claiming an improvement.

## Variable vector, fixed or parameterized PSD matrix

For x^T Q x with symmetric PSD data Q, prefer an available factor Q=R^T R:

```python
term = cp.sum_squares(R @ x)
```

Keep residuals such as `cp.sum_squares(A @ x - b)` in residual form; do not form
A^T A merely to use a quadratic-form atom. Sparse or rectangular factors can
preserve structure. A factor can also be a `cp.Parameter`; compute the factor
outside CVXPY and check `problem.is_dcp(dpp=True)` on the concrete problem.
Changing factors does not guarantee solver factorization reuse.

NumPy's Cholesky returns L with Q=L L^T: use R=L^T, not L. Cholesky requires
positive definiteness and can fail for valid singular PSD data. A known
rectangular factor handles that case. If deriving a factor spectrally, justify
the PSD tolerance, quantify reconstruction error, and preserve zero eigenvalues.
Do not silently clip genuinely negative eigenvalues or add a ridge term.
Include factorization cost and memory in any performance comparison.

`cp.quad_form(x, Q)` remains a valid option for suitable PSD data when a factor
would destroy useful structure or be disproportionately expensive. Distinguish
a numerical PSD-certification failure from an indefinite matrix using the data's
construction, factor, or appropriate numerical evidence. `psd_wrap` and
`assume_PSD=True` assert an assumption; they do not establish it. Never use them
to conceal indefinite or unverified data.

## Fixed vector, variable matrix

For fixed a and variable X, a^T X a is affine, regardless of whether X is PSD:

```python
# a has shape (n,), X has shape (n, n)
C = np.outer(a, a)
term = cp.trace(X @ C)
# Equivalent Frobenius contraction:
term = cp.sum(cp.multiply(C, X))
```

Here C is symmetric, so the elementwise contraction equals the trace expression.
For general fixed B, trace(B X) instead uses the contraction with B^T. Preserve
that transpose; not every coefficient matrix is symmetric. For many fixed
vectors, a sparse coefficient operator or contractions can avoid dense outer
products. Check dimensions and original expression values on supplied data.

Retain any requested symmetry/PSD domain of X. These affine expressions do not
require adding a PSD constraint. A model with a PSD matrix variable is outside
`cvx-model`'s LP/QP/SOCP scope unless an exact in-scope representation is justified;
`cvx-debug` can still diagnose its expression without expanding modeling scope.

If both x and Q are variables, neither replacement makes x^T Q x affine or
generally convex. Do not replace it with trace(Q X) and drop X=x x^T; that is a
different model, often a relaxation.

Sources: [CVXPY DPP](https://www.cvxpy.org/tutorial/dpp/index.html),
[atoms](https://www.cvxpy.org/tutorial/functions/index.html).
Loading
Loading