diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..c67382f --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,72 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Commands + +**Run tests:** +```julia +using Pkg; Pkg.test("TableauSimplex") +``` +Or from the Julia REPL package manager (`]`): +``` +test TableauSimplex +``` + +**Load the package interactively:** +```julia +using Pkg; Pkg.activate("."); using TableauSimplex +``` + +**Run an example script:** +```bash +julia --project examples/flights.jl +julia --project examples/network.jl +``` + +There is no linter or formatter configured for this project. + +## Architecture + +All logic lives in two files: `src/TableauSimplex.jl` (module + exports) and `src/functions.jl` (all implementations). + +### Core data structure + +`Tableau{T <: Number}` holds three fields: +- `table::Matrix{T}` — the full tableau matrix. Row 1 is the objective row (stores negated reduced costs in columns 1..n and the negated objective value in the last column). Rows 2..end are constraint rows. The last column of every row is the RHS. +- `basis::Vector{Int}` — length-`m` vector of column indices currently in the basis (one per constraint row). +- `varnames::Vector{String}` — human-readable names for all `n` decision+slack variables. + +The type parameter `T` propagates through all operations. Using `Rational{Int}` gives exact arithmetic; `Float64` is the default for numeric input. + +### Tableau construction + +`tableau(A, b, c)` builds a standard-form LP tableau by appending an identity block for slack variables. The basis is initialized to the slack variable indices `n+1:n+m`. + +You can also construct a `Tableau` directly, as in the examples, when a non-standard initial basis or variable naming is needed. + +### Mutating vs. copying conventions + +Every algorithm has two variants: +- `func!(Tab, ...)` — mutates `Tab` in place and returns it. +- `func(Tab, ...)` — copies `Tab` first via `copy(Tab)`, then calls `func!` on the copy. + +This applies to `simplex`/`simplex!`, `dualsimplex`/`dualsimplex!`, `simplexpivot`/`simplexpivot!`, `dualsimplexpivot`/`dualsimplexpivot!`, and `pivot`/`pivot!`. + +### Algorithms + +**Primal simplex** (`simplex!`): Dantzig's rule (most-negative reduced cost) for entering variable, minimum-ratio test for leaving variable. Detects unboundedness. + +**Dual simplex** (`dualsimplex!`): Most-negative RHS for leaving variable, minimum-ratio test on the objective row for entering variable. Detects infeasibility. + +**Integer programming** (`solveip`): Solves the LP relaxation, then iteratively adds Gomory cuts (`addGomorycuts`) for fractional basic variables and re-optimizes with dual simplex until all RHS values are integer. Randomly selects among fractional variables each iteration; not deterministic. Accepts either `(Tab)` or `(A, b, c)` (which requires integer `A` and `b`). + +### Display + +The global `__show_mode__` (`:compact` by default, can be set to `:full`) controls the `show` method. In compact mode, columns for basic variables are suppressed — only non-basic variable columns are printed, alongside the RHS. + +`clean!(Tab)` re-pivots each basic variable's column back to a unit vector; useful after manually constructing or splicing a tableau to restore canonical form. + +### Utility + +`num2string` pretty-prints numbers: zero becomes `""`, `Rational{Int}` prints as `p/q`, and other types use Julia's default string conversion.