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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ it releases that version ([RELEASING.md](https://github.com/energy-models/mathsp

## Upcoming version

- fix(language): dual(c) is the rate at which the optimal objective rises with the right side of c, so an equality has a sign too ([#751](https://github.com/energy-models/mathspec/pull/751))
- fix(language): a macro formal written inside a list takes the name the call binds to it ([#779](https://github.com/energy-models/mathspec/pull/779))
- feat(language): a sum names several dimensions in one over= list ([#778](https://github.com/energy-models/mathspec/pull/778))
- feat(language): a divisor or a power over parameters may add, so a discount factor is written where it is used ([#757](https://github.com/energy-models/mathspec/pull/757))
Expand Down
15 changes: 12 additions & 3 deletions docs/reference/language/named.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,9 +176,18 @@ Constraint 'd': a dual exists only after a solve; the math cannot read one —
keep the entry that carries it out of constraints, the objective, bounds and where.
```

`dual(c)` is the rate at which the optimal objective improves as `c` is relaxed
in the direction its comparator points, under the spec's own `minimize` or
`maximize`.
`dual(c)` is the rate at which the optimal objective rises as the right side
of `c` rises. Read `lhs <= rhs` as `lhs <= rhs + d`: the dual is the rate in `d`
at `d = 0`. The rule is the same for `<=`, `>=` and `==`, and under `minimize`
and `maximize`, so an equality has a dual with a sign too. Which side a term is
written on decides the sign: `p <= cap` and `-p >= -cap` state one row, and their
duals are opposite.

| Under `minimize`, a binding row | Its dual |
| ------------------------------- | ------------------------------------ |
| `p <= cap` | at most 0 |
| `p >= load` | at least 0 |
| `sum(p, over=g) == load` | the price of one more unit of `load` |

A row that `c`'s `where:` deletes has no dual.

Expand Down
14 changes: 8 additions & 6 deletions src/mathspec/program.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,12 +189,14 @@ class Variable:

@dataclass(frozen=True)
class Dual:
"""A constraint's dual — its shadow price, read after the solve.

Stands only under an [`ExpressionDeclaration`][] the math never reads:
the loader refuses ``dual()`` anywhere a solver ingests. One value per
coordinate of the named constraint's own ``dims`` frame: the leaf reshapes
nothing, like a parameter.
"""A constraint's dual — the rate the optimal objective rises with the constraint's right side, read after the solve.

Of ``lhs <= rhs`` it is the rate in ``d`` of ``lhs <= rhs + d``, for every
comparator and under either sense. Stands only under an
[`ExpressionDeclaration`][] the math never reads: the loader refuses
``dual()`` anywhere a solver ingests. One value per coordinate of the named
constraint's own ``dims`` frame: the leaf reshapes nothing, like a
parameter.
"""

constraint: str
Expand Down
Loading