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
4 changes: 2 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ CTSolversZygote = "Zygote"
ADNLPModels = "0.8"
Aqua = "0.8"
BenchmarkTools = "1"
CTBase = "0.18, 0.20"
CTModels = "0.11"
CTBase = "0.21"
CTModels = "0.12"
CUDA = "5, 6"
CommonSolve = "0.2"
DocStringExtensions = "0.9"
Expand Down
2 changes: 1 addition & 1 deletion docs/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ DocumenterMermaid = "a078cd44-4d9c-4618-b545-3ab9d77f9177"
MarkdownAST = "d0879d2d-cac2-40c8-9cee-1863dc0c7391"

[compat]
CTBase = "0.18, 0.20"
CTBase = "0.21"
Documenter = "1"
DocumenterMermaid = "0.2"
MarkdownAST = "0.1"
Expand Down
106 changes: 0 additions & 106 deletions docs/api_reference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -105,49 +105,6 @@ function generate_api_reference(src_dir::String, ext_dir::String)
filename="optimization",
),

# ───────────────────────────────────────────────────────────────────
# Options
# ───────────────────────────────────────────────────────────────────
CTBase.automatic_reference_documentation(;
subdirectory="api",
primary_modules=[
CTSolvers.Options => src(
joinpath("Options", "Options.jl"),
joinpath("Options", "extraction.jl"),
joinpath("Options", "not_provided.jl"),
joinpath("Options", "option_definition.jl"),
joinpath("Options", "option_value.jl"),
),
],
exclude=EXCLUDE_SYMBOLS,
public=true,
private=true,
title="Options",
title_in_menu="Options",
filename="options",
),

# ───────────────────────────────────────────────────────────────────
# Orchestration
# ───────────────────────────────────────────────────────────────────
CTBase.automatic_reference_documentation(;
subdirectory="api",
primary_modules=[
CTSolvers.Orchestration => src(
joinpath("Orchestration", "Orchestration.jl"),
joinpath("Orchestration", "builders.jl"),
joinpath("Orchestration", "disambiguation.jl"),
joinpath("Orchestration", "routing.jl"),
),
],
exclude=EXCLUDE_SYMBOLS,
public=true,
private=true,
title="Orchestration",
title_in_menu="Orchestration",
filename="orchestration",
),

# ───────────────────────────────────────────────────────────────────
# Solvers
# ───────────────────────────────────────────────────────────────────
Expand All @@ -174,69 +131,6 @@ function generate_api_reference(src_dir::String, ext_dir::String)
filename="solvers",
),

# ───────────────────────────────────────────────────────────────────
# Strategies — Contract (abstract types, default implementations)
# ───────────────────────────────────────────────────────────────────
CTBase.automatic_reference_documentation(;
subdirectory="api",
primary_modules=[
CTSolvers.Strategies => src(
joinpath("Strategies", "Strategies.jl"),
joinpath("Strategies", "contract", "abstract_strategy.jl"),
joinpath("Strategies", "contract", "metadata.jl"),
joinpath("Strategies", "contract", "parameters.jl"),
joinpath("Strategies", "contract", "strategy_options.jl"),
),
],
exclude=EXCLUDE_SYMBOLS,
public=true,
private=true,
title="Strategies — Contract",
title_in_menu="Strategies (Contract)",
filename="strategies_contract",
),

# ───────────────────────────────────────────────────────────────────
# Strategies — API (registry, builders, introspection, configuration)
# ───────────────────────────────────────────────────────────────────
CTBase.automatic_reference_documentation(;
subdirectory="api",
primary_modules=[
CTSolvers.Strategies => src(
joinpath("Strategies", "api", "builders.jl"),
joinpath("Strategies", "api", "bypass.jl"),
joinpath("Strategies", "api", "configuration.jl"),
joinpath("Strategies", "api", "describe_registry.jl"),
joinpath("Strategies", "api", "disambiguation.jl"),
joinpath("Strategies", "api", "introspection.jl"),
joinpath("Strategies", "api", "registry.jl"),
joinpath("Strategies", "api", "utilities.jl"),
joinpath("Strategies", "api", "validation_helpers.jl"),
),
],
exclude=EXCLUDE_SYMBOLS,
public=true,
private=true,
title="Strategies — API",
title_in_menu="Strategies (API)",
filename="strategies_api",
),

# ───────────────────────────────────────────────────────────────────
# Strategies — Display Formatting
# ─────────────────────────────────────────────────────────────────--
CTBase.automatic_reference_documentation(;
subdirectory="api",
primary_modules=[
CTSolvers.Strategies => src(joinpath("Strategies", "display_formatting.jl"))
],
exclude=EXCLUDE_SYMBOLS,
public=true,
private=true,
title="Strategies — Display Formatting",
title_in_menu="Strategies (Display)",
filename="strategies_display",
),
]

# ───────────────────────────────────────────────────────────────────
Expand Down
4 changes: 0 additions & 4 deletions docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,9 @@ with_api_reference(src_dir, ext_dir) do api_pages
"Introduction" => "index.md",
"Architecture" => "architecture.md",
"Developer Guides" => [
"Options System" => "guides/options_system.md",
"Implementing a Strategy" => "guides/implementing_a_strategy.md",
"Strategy Parameters" => "guides/strategy_parameters.md",
"Implementing a Solver" => "guides/implementing_a_solver.md",
"Implementing a Modeler" => "guides/implementing_a_modeler.md",
"Implementing an Optimization Problem" => "guides/implementing_an_optimization_problem.md",
"Orchestration & Routing" => "guides/orchestration_and_routing.md",
"Error Messages Reference" => "guides/error_messages.md",
],
"API Reference" => api_pages,
Expand Down
60 changes: 35 additions & 25 deletions docs/src/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,34 @@ This page provides the complete architectural overview. Read it before diving in

## Module Overview

CTSolvers is organized into 7 modules, loaded in strict dependency order:
CTSolvers relies on **CTBase** for its generic infrastructure and adds CTSolvers-specific modules:

### Generic infrastructure (provided by CTBase)

| Module | Responsibility |
|--------|---------------|
| **CTBase.Options** | Configuration primitives: `OptionDefinition`, `OptionValue`, extraction, validation |
| **CTBase.Strategies** | Strategy contract (`AbstractStrategy`), registry, metadata, options building |
| **CTBase.Orchestration** | Multi-strategy option routing and disambiguation |

### CTSolvers-specific modules, loaded in dependency order

| # | Module | Responsibility |
|---|--------|---------------|
| 1 | **Options** | Configuration primitives: `OptionDefinition`, `OptionValue`, extraction, validation |
| 2 | **Strategies** | Strategy contract (`AbstractStrategy`), registry, metadata, options building |
| 3 | **Orchestration** | Multi-strategy option routing and disambiguation |
| 4 | **Optimization** | Abstract optimization types (`AbstractOptimizationProblem`), builders, `build_model`/`build_solution` |
| 5 | **Modelers** | NLP model backends: `Modelers.ADNLP`, `Modelers.Exa` |
| 6 | **DOCP** | `DiscretizedModel` — bridges CTModels and CTSolvers |
| 7 | **Solvers** | Solver integration: `Solvers.Ipopt`, `Solvers.MadNLP`, `Solvers.MadNCL`, `Solvers.Knitro`, CommonSolve API |
| 1 | **Optimization** | Abstract optimization types (`AbstractOptimizationProblem`), builders, `build_model`/`build_solution` |
| 2 | **Modelers** | NLP model backends: `Modelers.ADNLP`, `Modelers.Exa` |
| 3 | **DOCP** | `DiscretizedModel` — bridges CTModels and CTSolvers |
| 4 | **Solvers** | Solver integration: `Solvers.Ipopt`, `Solvers.MadNLP`, `Solvers.MadNCL`, `Solvers.Knitro`, CommonSolve API |

All access is **qualified** — CTSolvers does not export symbols at the top level:
All access is **qualified** — neither CTBase nor CTSolvers export symbols at the top level:

```julia
using CTSolvers
using CTBase

# Correct: qualified access
CTSolvers.Strategies.id(MyStrategy)
CTSolvers.Options.OptionDefinition(name=:x, type=Int, default=1, description="...")
CTBase.Strategies.id(MyStrategy)
CTBase.Options.OptionDefinition(name=:x, type=Int, default=1, description="...")

# Wrong: not exported
id(MyStrategy) # ERROR: UndefVarError
Expand Down Expand Up @@ -79,7 +87,7 @@ classDiagram
Other packages in the control-toolbox ecosystem define additional strategy families:
- **`AbstractDiscretizer`** (in [CTDirect.jl](https://github.com/control-toolbox/CTDirect.jl)): discretizes continuous-time OCP into finite-dimensional problems (e.g., `Collocation`, `DirectShooting`).

These external strategies follow the same `AbstractStrategy` contract. See [Implementing a Strategy](@ref) for a complete tutorial.
These external strategies follow the same `AbstractStrategy` contract. See the Implementing a Strategy guide in CTBase.jl documentation for a complete tutorial.

### Optimization / Builder Branch

Expand Down Expand Up @@ -127,8 +135,10 @@ classDiagram

```mermaid
flowchart LR
Options --> Strategies
Strategies --> Orchestration
subgraph CTBase
Options --> Strategies
Strategies --> Orchestration
end
Strategies --> Optimization
Strategies --> Modelers
Strategies --> Solvers
Expand All @@ -140,10 +150,10 @@ flowchart LR
Modelers --> Solvers
```

The loading order in `CTSolvers.jl` is:
The loading order is: CTBase loads Options → Strategies → Orchestration first; then CTSolvers loads:

```
Options → Strategies → Orchestration → Optimization → Modelers → DOCP → Solvers
Optimization → Modelers → DOCP → Solvers
```

Each module only depends on modules loaded before it. This strict ordering ensures:
Expand Down Expand Up @@ -218,7 +228,7 @@ flowchart TB
- **Type-level methods** (`id`, `metadata`) are called on the **type** — they enable introspection, routing, and validation without creating objects.
- **Instance-level methods** (`options`) are called on **instances** — they provide the actual configuration with provenance tracking.

See [Implementing a Strategy](@ref) for a step-by-step tutorial.
See the Implementing a Strategy guide in CTBase.jl documentation for a step-by-step tutorial.

### Strategy Parameters (Overview)

Expand Down Expand Up @@ -248,15 +258,15 @@ flowchart TB
- **Specialized defaults** per parameter (e.g., different linear solvers for CPU/GPU)
- **Type-based metadata** via `metadata(::Type{<:Strategy}, ::Type{<:Parameter})`

See [Strategy Parameters](@ref) for a complete guide.
See the Strategy Parameters guide in CTBase.jl documentation for a complete guide.

### NotImplemented Pattern

All contract methods have default implementations that throw `NotImplemented` with helpful error messages:

```julia
# If you forget to implement `id` for your strategy:
julia> Strategies.id(IncompleteStrategy)
julia> CTBase.Strategies.id(IncompleteStrategy)
# ERROR: NotImplemented
# Strategy ID method not implemented
# Required method: id(::Type{<:IncompleteStrategy})
Expand Down Expand Up @@ -296,8 +306,8 @@ flowchart LR
CTSolvers does **not** export symbols at the top level. All access goes through qualified module paths:

```julia
CTSolvers.Strategies.id(MyStrategy)
CTSolvers.Options.OptionDefinition(...)
CTBase.Strategies.id(MyStrategy)
CTBase.Options.OptionDefinition(...)
CTSolvers.Optimization.build_model(problem, x0, modeler)
```

Expand All @@ -319,7 +329,7 @@ Every strategy constructor follows the same pattern:

```julia
function MyStrategy(; mode::Symbol = :strict, kwargs...)
opts = Strategies.build_strategy_options(MyStrategy; mode = mode, kwargs...)
opts = CTBase.Strategies.build_strategy_options(MyStrategy; mode = mode, kwargs...)
return MyStrategy(opts)
end
```
Expand All @@ -332,14 +342,14 @@ end
Options are declared via `OptionDefinition` in the `metadata` method:

```julia
Strategies.metadata(::Type{<:MyStrategy}) = Strategies.StrategyMetadata(
Options.OptionDefinition(
CTBase.Strategies.metadata(::Type{<:MyStrategy}) = CTBase.Strategies.StrategyMetadata(
CTBase.Options.OptionDefinition(
name = :max_iter,
type = Int,
default = 1000,
description = "Maximum number of iterations",
),
Options.OptionDefinition(
CTBase.Options.OptionDefinition(
name = :tol,
type = Float64,
default = 1e-8,
Expand Down
Loading
Loading