Skip to content

Public API

This page lists exported symbols of CTBase.Strategies.


From CTBase.Strategies

CTBase.Strategies [Module]

CTBase.Strategies Module

Strategy management and registry for the Control Toolbox ecosystem.

This module provides:

  • Abstract strategy contract and interface

  • Strategy registry for explicit dependency management

  • Strategy building and validation utilities

  • Metadata management for strategy families

The Strategies module depends on Options for option handling but provides higher-level strategy management capabilities.

AbstractStrategy [Abstract Type]

CTBase.Strategies.AbstractStrategy Type
julia
abstract type AbstractStrategy

Abstract base type for all strategies in the control-toolbox ecosystem.

Every concrete strategy must implement a two-level contract separating static type metadata from dynamic instance configuration.

Contract Overview

Type-Level Contract (Static Metadata)

Methods defined on the type that describe what the strategy can do:

  • id(::Type{<:MyStrategy})::Symbol - Unique identifier for routing and introspection

  • metadata(::Type{<:MyStrategy})::StrategyMetadata - Option specifications and validation rules

Why type-level? These methods enable:

  • Introspection without instantiation - Query capabilities without creating objects

  • Routing and dispatch - Select strategies by symbol for automated construction

  • Validation before construction - Verify compatibility before resource allocation

Instance-Level Contract (Configured State)

Methods defined on instances that provide the actual configuration:

  • options(strategy::MyStrategy)::StrategyOptions - Current option values with provenance tracking

Why instance-level? These methods enable:

  • Multiple configurations - Different instances with different settings

  • Provenance tracking - Know which options came from user vs defaults

  • Encapsulation - Configuration state belongs to the executing object

Implementation Requirements

Every concrete strategy must provide:

  1. Type definition with an options::StrategyOptions field (recommended)

  2. Type-level methods for id and metadata

  3. Constructor accepting keyword arguments (uses build_strategy_options)

  4. Instance-level access to configured options

Validation Modes

The strategy system supports two validation modes for option handling:

  • Strict Mode (default): Rejects unknown options with detailed error messages

    • Provides early error detection and safety

    • Suggests corrections for typos using Levenshtein distance

    • Ideal for development and production environments

  • Permissive Mode: Accepts unknown options with warnings

    • Allows backend-specific options without breaking changes

    • Maintains validation for known options (types, custom validators)

    • Ideal for advanced users and experimental features

The validation mode is controlled by the mode parameter in constructors:

julia
# Strict mode (default) - rejects unknown options
julia> MyStrategy(unknown_option=123)  # ERROR

# Permissive mode - accepts unknown options with warning
julia> MyStrategy(unknown_option=123; mode=:permissive)  # WARNING but works

API Methods

The Strategies module provides these methods for working with strategies:

  • id(strategy_type) - Get the unique identifier

  • metadata(strategy_type) - Get option specifications

  • options(strategy) - Get current configuration

  • build_strategy_options(Type; mode=:strict, kwargs...) - Validate and merge options

Example

julia
# Define strategy type
julia> struct MyStrategy <: AbstractStrategy
           options::StrategyOptions
       end

# Implement type-level contract
julia> id(::Type{<:MyStrategy}) = :mystrategy
julia> metadata(::Type{<:MyStrategy}) = StrategyMetadata(
           OptionDefinition(name=:max_iter, type=Int, default=100, description="Max iterations")
       )

# Implement constructor (required)
julia> function MyStrategy(; mode::Symbol=:strict, kwargs...)
           options = build_strategy_options(MyStrategy; mode=mode, kwargs...)
           return MyStrategy(options)
       end

# Use the strategy
julia> strategy = MyStrategy(max_iter=200)  # Instance with custom config (strict mode)
julia> id(typeof(strategy))                 # => :mystrategy (type-level)
julia> options(strategy)                    # => StrategyOptions (instance-level)

# Use with permissive mode for unknown options
julia> strategy = MyStrategy(max_iter=200, custom_option=123; mode=:permissive)

Notes

  • Type-level methods are called on the type: id(MyStrategy)

  • Instance-level methods are called on instances: options(strategy)

  • Constructor pattern is required for registry-based construction

  • Strategy families can be created with intermediate abstract types

AbstractStrategyParameter [Abstract Type]

CTBase.Strategies.AbstractStrategyParameter Type

Abstract base type for strategy parameters.

Strategy parameters allow specialization of strategy behavior and default options. Every concrete parameter must implement:

  • id(::Type{<:AbstractStrategyParameter})::Symbol - Unique identifier

Examples

julia
struct CPU <: AbstractStrategyParameter end
id(::Type{CPU}) = :cpu

struct GPU <: AbstractStrategyParameter end
id(::Type{GPU}) = :gpu

Notes

  • Parameters are singleton types (no fields) - they exist only for type dispatch

  • IDs must be globally unique across all strategies and parameters

  • Parameters are used to specialize default options in strategy metadata

BypassValue [Struct]

CTBase.Strategies.BypassValue Type
julia
struct BypassValue{T}

Wrapper type for option values that should bypass validation.

This type is used to explicitly skip validation for specific options when constructing strategies. It is particularly useful for passing backend-specific options that are not defined in the strategy's metadata.

Fields

  • value::T: The wrapped option value

Example

julia
julia> val = bypass(42)
BypassValue(42)

See also: bypass

CPU [Struct]

CTBase.Strategies.CPU Type

CPU parameter type for CPU-based computation.

This parameter indicates that a strategy should use CPU-based backends and default options optimized for CPU execution.

GPU [Struct]

CTBase.Strategies.GPU Type

GPU parameter type for GPU-based computation.

This parameter indicates that a strategy should use GPU-based backends and default options optimized for GPU execution.

Notes

  • Requires CUDA.jl to be loaded and functional

  • Strategies may throw CTBase.Exceptions.ExtensionError if CUDA is not available

RoutedOption [Struct]

CTBase.Strategies.RoutedOption Type
julia
struct RoutedOption

Routed option value with explicit strategy targeting.

This type is created by route_to to disambiguate options that exist in multiple strategies. It wraps one or more (strategy_id => value) pairs, allowing the orchestration layer to route each value to its intended strategy.

Fields

  • routes::NamedTuple: NamedTuple of strategy_id => value mappings

Iteration

RoutedOption implements the collection interface and can be iterated like a dictionary:

  • keys(opt): Strategy IDs

  • values(opt): Option values

  • pairs(opt): (strategy_id, value) pairs

  • for (id, val) in opt: Direct iteration over pairs

  • opt[:strategy]: Index by strategy ID

  • haskey(opt, :strategy): Check if strategy exists

  • length(opt): Number of routes

Example

julia
julia> using CTBase.Strategies

julia> # Single strategy
julia> opt = route_to(solver=100)
RoutedOption((solver = 100,))

julia> # Multiple strategies
julia> opt = route_to(solver=100, modeler=50)
RoutedOption((solver = 100, modeler = 50))

julia> # Iterate over routes
julia> for (id, val) in opt
           println("$id => $val")
       end
solver => 100
modeler => 50

See also: route_to

StrategyMetadata [Struct]

CTBase.Strategies.StrategyMetadata Type
julia
struct StrategyMetadata{NT<:NamedTuple}

Metadata about a strategy type, wrapping option definitions.

This type serves as a container for OptionDefinition objects that define the contract for a strategy's configuration options. It is returned by the type-level metadata(::Type{<:AbstractStrategy}) method and provides a convenient interface for accessing and managing option definitions.

Strategy Contract

Every concrete strategy type must implement the metadata method to return a StrategyMetadata instance describing its configurable options:

julia
function metadata(::Type{<:MyStrategy})
    return StrategyMetadata(
        OptionDefinition(...),
        OptionDefinition(...),
        # ... more option definitions
    )
end

This metadata is used by:

  • Validation: Check option types and values before construction

  • Documentation: Auto-generate option documentation

  • Introspection: Query available options without instantiation

  • Construction: Build StrategyOptions with build_strategy_options

Fields

  • specs::NamedTuple: NamedTuple mapping option names to their definitions (type-stable)

Type Parameter

  • NT <: NamedTuple: The concrete NamedTuple type holding the option definitions

Constructor

The constructor accepts a variable number of OptionDefinition arguments and automatically builds the internal NamedTuple, validating that all option names are unique. The type parameter is inferred automatically.

Collection Interface

StrategyMetadata implements standard Julia collection interfaces:

  • meta[:option_name] - Access definition by name

  • keys(meta) - Get all option names

  • values(meta) - Get all definitions

  • pairs(meta) - Iterate over name-definition pairs

  • length(meta) - Number of options

Example - Standalone Usage

julia
julia> using CTBase.Strategies

julia> meta = StrategyMetadata(
           OptionDefinition(
               name = :max_iter,
               type = Int,
               default = 100,
               description = "Maximum iterations",
               aliases = (:max, :maxiter),
               validator = x -> x > 0 || throw(ArgumentError("$x must be positive"))
           ),
           OptionDefinition(
               name = :tol,
               type = Float64,
               default = 1e-6,
               description = "Convergence tolerance"
           )
       )
StrategyMetadata with 2 options:
  max_iter (max, maxiter) :: Int64
    default: 100
    description: Maximum iterations
  tol :: Float64
    default: 1.0e-6
    description: Convergence tolerance

julia> meta[:max_iter].name
:max_iter

julia> collect(keys(meta))
2-element Vector{Symbol}:
 :max_iter
 :tol

Example - Strategy Implementation

julia
# Define a concrete strategy type
struct MyOptimizer <: AbstractStrategy
    options::StrategyOptions
end

# Implement the metadata contract (type-level)
function metadata(::Type{<:MyOptimizer})
    return StrategyMetadata(
        OptionDefinition(
            name = :max_iter,
            type = Int,
            default = 100,
            description = "Maximum number of iterations",
            validator = x -> x > 0 || throw(ArgumentError("max_iter must be positive"))
        ),
        OptionDefinition(
            name = :tol,
            type = Float64,
            default = 1e-6,
            description = "Convergence tolerance",
            validator = x -> x > 0 || throw(ArgumentError("tol must be positive"))
        )
    )
end

# Implement the id contract (type-level)
id(::Type{<:MyOptimizer}) = :myoptimizer

# Implement constructor using build_strategy_options
function MyOptimizer(; kwargs...)
    options = build_strategy_options(MyOptimizer; kwargs...)
    return MyOptimizer(options)
end

# Now the strategy can be used with automatic validation
julia> strategy = MyOptimizer(max_iter=200, tol=1e-8)
julia> options(strategy)
StrategyOptions(max_iter=200, tol=1.0e-8)

Throws

  • Exceptions.IncorrectArgument: If duplicate option names are provided

See also: OptionDefinition, AbstractStrategy, build_strategy_options

StrategyOptions [Struct]

CTBase.Strategies.StrategyOptions Type
julia
struct StrategyOptions{NT<:NamedTuple}

Wrapper for strategy option values with provenance tracking.

This type stores options as a collection of OptionValue objects, each containing both the value and its source (:user, :default, or :computed).

Validation Modes

Strategy options are built using build_strategy_options() which supports two validation modes:

  • Strict Mode (default): Only known options are accepted

    • Unknown options trigger detailed error messages with suggestions

    • Type validation and custom validators are enforced

    • Provides early error detection and safety

  • Permissive Mode: Unknown options are accepted with warnings

    • Unknown options are stored with :user source

    • Type validation and custom validators still apply to known options

    • Allows backend-specific options without breaking changes

Fields

  • options::NamedTuple: NamedTuple of OptionValue objects with provenance

  • alias_map::Dict{Symbol, Symbol}: Mapping from alias names to canonical names

Construction

julia
julia> using CTBase.Strategies, CTBase.Options

julia> opts = StrategyOptions(
           max_iter = OptionValue(200, :user),
           tol = OptionValue(1e-6, :default)
       )
StrategyOptions with 2 options:
  max_iter = 200  [user]
  tol = 1.0e-6  [default]

Building Options with Validation

julia
# Strict mode (default) - rejects unknown options
julia> opts = build_strategy_options(MyStrategy; max_iter=200)
StrategyOptions(...)

# Permissive mode - accepts unknown options with warning
julia> opts = build_strategy_options(MyStrategy; max_iter=200, custom_opt=123; mode=:permissive)
StrategyOptions(...)  # with warning about custom_opt

Access patterns

julia
# Get value only (canonical name)
julia> opts[:max_iter]
200

# Get value using alias
julia> opts[:maxiter]  # Alias automatically resolved
200

# Get OptionValue (value + source)
julia> opts.max_iter
OptionValue(200, :user)

# Get source only
julia> source(opts, :max_iter)
:user

# Check if user-provided
julia> is_user(opts, :max_iter)
true

# Check if option exists (works with aliases)
julia> haskey(opts, :maxiter)
true

Iteration

julia
# Iterate over values
julia> for value in opts
           println(value)
       end

# Iterate over (name, value) pairs
julia> for (name, value) in opts
           println("$name = $value")
       end

See also: OptionValue, source, is_user, is_default, is_computed

StrategyRegistry [Struct]

CTBase.Strategies.StrategyRegistry Type
julia
struct StrategyRegistry

Registry mapping strategy families to their concrete types.

This type provides an explicit, immutable registry for managing strategy types organized by family. It enables:

  • Type lookup by ID: Find concrete types from symbolic identifiers

  • Family introspection: List all strategies in a family

  • Validation: Ensure ID uniqueness and type hierarchy correctness

Design Philosophy

The registry uses an explicit passing pattern rather than global mutable state:

  • Created once via create_registry

  • Passed explicitly to functions that need it

  • Thread-safe (no shared mutable state)

  • Testable (easy to create multiple registries)

Fields

  • families::Dict{Type{<:AbstractStrategy}, Vector{Type}}: Maps abstract family types to concrete strategy types

Example

julia
julia> using CTBase.Strategies

julia> registry = create_registry(
           AbstractNLPModeler => (Modelers.ADNLP, Modelers.Exa),
           AbstractNLPSolver => (Solvers.Ipopt, Solvers.MadNLP)
       )
StrategyRegistry with 2 families

julia> strategy_ids(AbstractNLPModeler, registry)
(:adnlp, :exa)

julia> T = type_from_id(:adnlp, AbstractNLPModeler, registry)
Modelers.ADNLP

See also: create_registry, strategy_ids, type_from_id

available_parameters [Function]

CTBase.Strategies.available_parameters Function
julia
available_parameters(
    strategy_id::Symbol,
    family::Type{<:CTBase.Strategies.AbstractStrategy},
    registry::CTBase.Strategies.StrategyRegistry
) -> Vector{Type{<:CTBase.Strategies.AbstractStrategyParameter}}

Return all available strategy parameter types for a given (strategy_id, family).

This function is used by orchestration to validate that a global parameter token present in the method tuple is compatible with all selected strategies.

Arguments

  • strategy_id::Symbol: Strategy identifier (e.g. :madnlp).

  • family::Type{<:AbstractStrategy}: Family to search within.

  • registry::StrategyRegistry: Strategy registry.

Returns

  • Vector{Type{<:AbstractStrategyParameter}}: Supported parameter types. Returns an empty vector if the strategy is not parameterized.

See also: extract_global_parameter_from_method, get_parameter_type

build_strategy [Function]

CTBase.Strategies.build_strategy Function
julia
build_strategy(
    id::Symbol,
    family::Type{<:CTBase.Strategies.AbstractStrategy},
    registry::CTBase.Strategies.StrategyRegistry;
    mode,
    kwargs...
) -> Any

Build a strategy instance from its ID and options.

This function creates a concrete strategy instance by:

  1. Looking up the strategy type from its ID in the registry

  2. Constructing the instance with the provided options

Arguments

  • id::Symbol: Strategy identifier (e.g., :adnlp, :ipopt)

  • family::Type{<:AbstractStrategy}: Abstract family type to search within

  • registry::StrategyRegistry: Registry containing strategy mappings

  • mode::Symbol=:strict: Validation mode (:strict or :permissive)

  • kwargs...: Options to pass to the strategy constructor

Returns

  • Concrete strategy instance of the appropriate type

Throws

  • Exceptions.IncorrectArgument: If the strategy ID is not found in the registry for the given family

Example

julia
julia> registry = create_registry(
           AbstractNLPModeler => (Modelers.ADNLP, Modelers.Exa)
       )

julia> modeler = build_strategy(:adnlp, AbstractNLPModeler, registry; backend=:sparse)
Modelers.ADNLP(options=StrategyOptions{...})

julia> modeler = build_strategy(:adnlp, AbstractNLPModeler, registry; 
           backend=:sparse, mode=:permissive)
Modelers.ADNLP(options=StrategyOptions{...})

See also: type_from_id

julia
build_strategy(
    id::Symbol,
    parameter::Type{<:CTBase.Strategies.AbstractStrategyParameter},
    family::Type{<:CTBase.Strategies.AbstractStrategy},
    registry::CTBase.Strategies.StrategyRegistry;
    mode,
    kwargs...
) -> Any

Build a parameterized strategy instance from ID, parameter, and options.

This function creates a concrete parameterized strategy instance by:

  1. Looking up the parameterized strategy type from its ID and parameter

  2. Constructing the instance with the provided options

Arguments

  • id::Symbol: Strategy identifier (e.g., :madnlp)

  • parameter::Type{<:AbstractStrategyParameter}: Parameter type (e.g., GPU)

  • family::Type{<:AbstractStrategy}: Abstract family type to search within

  • registry::StrategyRegistry: Registry containing strategy mappings

  • mode::Symbol=:strict: Validation mode (:strict or :permissive)

  • kwargs...: Options to pass to the strategy constructor

Returns

  • Concrete parameterized strategy instance (e.g., MadNLP{GPU})

Throws

  • CTBase.Exceptions.IncorrectArgument: If the strategy-parameter combination is not found

Example

julia
julia> registry = create_registry(
           AbstractNLPSolver => ((MadNLP, [CPU, GPU]),)
       )

julia> solver = build_strategy(:madnlp, GPU, AbstractNLPSolver, registry; max_iter=1000)
MadNLP{GPU}(options=StrategyOptions{...})

See also: build_strategy

build_strategy_options [Function]

CTBase.Strategies.build_strategy_options Function
julia
build_strategy_options(
    strategy_type::Type{<:CTBase.Strategies.AbstractStrategy};
    mode,
    kwargs...
)

Build StrategyOptions from user kwargs and strategy metadata.

This function creates a StrategyOptions instance by:

  1. Validating the mode parameter (:strict or :permissive)

  2. Extracting known options from kwargs using the Options API

  3. Handling unknown options based on the mode

  4. Converting the extracted Dict to NamedTuple

  5. Wrapping in StrategyOptions

The Options.extract_options function handles:

  • Alias resolution to primary names

  • Type validation

  • Custom validators

  • Default values

  • Provenance tracking (:user, :default)

Arguments

  • strategy_type::Type{<:AbstractStrategy}: The strategy type to build options for

  • mode::Symbol = :strict: Validation mode (:strict or :permissive)

    • :strict (default): Rejects unknown options with detailed error message

    • :permissive: Accepts unknown options with warning, stores with :user source (unvalidated)

  • kwargs...: User-provided option values

Returns

  • StrategyOptions: Validated options with provenance tracking

Throws

  • Exceptions.IncorrectArgument: If mode is not :strict or :permissive

  • Exceptions.IncorrectArgument: If an unknown option is provided in strict mode

  • Exceptions.IncorrectArgument: If type validation fails (both modes)

  • Exceptions.IncorrectArgument: If custom validation fails (both modes)

Example

julia
# Define a minimal strategy for demonstration
julia> struct MyStrategy <: AbstractStrategy end
julia> Strategies.metadata(::Type{MyStrategy}) = StrategyMetadata(
           OptionDefinition(name=:max_iter, type=Int, default=100)
       )

# Strict mode (default) - rejects unknown options
julia> opts = build_strategy_options(MyStrategy; max_iter=200)
StrategyOptions with 1 option:
  max_iter = 200  [user]

# Permissive mode - accepts unknown options with warning
julia> opts = build_strategy_options(MyStrategy; max_iter=200, custom_opt=123, mode=:permissive)
┌ Warning: Unrecognized options passed to MyStrategy
│   Unvalidated options: [:custom_opt]
...
StrategyOptions with 2 options:
  max_iter = 200  [user]
  custom_opt = 123  [user]

Notes

  • Known options are always validated (type, custom validators) regardless of mode

  • Unknown options in permissive mode are stored with source :user but bypass validation

  • Use permissive mode only when you need to pass backend-specific options not defined in the strategy metadata

See also: StrategyOptions, metadata, Options.extract_options

bypass [Function]

CTBase.Strategies.bypass Function
julia
bypass(val) -> CTBase.Strategies.BypassValue

Mark an option value to bypass validation.

This function creates a BypassValue wrapper around the provided value. When passed to a strategy constructor, this value will be accepted even if the option name is unknown (not in metadata) or if validation would otherwise fail.

This can be combined with route_to to bypass validation for specific strategies when routing ambiguous options.

Arguments

  • val: The option value to wrap

Returns

  • BypassValue: The wrapped value

Example

julia
julia> using CTBase.Strategies

julia> # Pass an unknown option directly to strategy
julia> solver = Ipopt(
           max_iter=100, 
           custom_backend_option=bypass(42)  # Bypasses validation
       )
Ipopt(options=StrategyOptions{...})

julia> # Alternative syntax using force alias
julia> solver = Ipopt(
           max_iter=100, 
           custom_backend_option=force(42)  # Same as bypass(42)
       )
Ipopt(options=StrategyOptions{...})

julia> # Combine with routing for ambiguous options
julia> solve(ocp, method; 
           backend = route_to(ipopt=bypass(42))  # Route to ipopt AND bypass validation
       )

Notes

  • Use with caution! Bypassed options are passed directly to the backend.

  • Typos in option names will not be caught by validation.

  • Invalid values for the backend will cause backend-level errors.

  • Can be combined with route_to for strategy-specific bypassing

  • force is an alias for bypass - they are identical functions

See also: BypassValue, route_to, force

create_registry [Function]

CTBase.Strategies.create_registry Function
julia
create_registry(
    pairs::Pair...
) -> CTBase.Strategies.StrategyRegistry

Create a strategy registry from family-to-strategies mappings.

This function validates the registry structure and ensures:

  • All strategy IDs are unique within each family

  • All strategies are subtypes of their declared family

  • No duplicate family definitions

Arguments

  • pairs...: Pairs of family type => tuple of strategy types

Returns

  • StrategyRegistry: Validated registry ready for use

Validation Rules

  1. ID Uniqueness: Within each family, all strategy id() values must be unique

  2. Type Hierarchy: Each strategy must be a subtype of its family

  3. No Duplicates: Each family can only appear once in the registry

Example

julia
julia> using CTBase.Strategies

julia> registry = create_registry(
           AbstractNLPModeler => (Modelers.ADNLP, Modelers.Exa),
           AbstractNLPSolver => (Solvers.Ipopt, Solvers.MadNLP, Solvers.Knitro)
       )
StrategyRegistry with 2 families

julia> strategy_ids(AbstractNLPModeler, registry)
(:adnlp, :exa)

Throws

  • ErrorException: If duplicate IDs are found within a family

  • ErrorException: If a strategy is not a subtype of its family

  • ErrorException: If a family appears multiple times

See also: StrategyRegistry, strategy_ids, type_from_id

describe [Function]

CTBase.Strategies.describe Function

Display detailed information about a strategy type, including its id, supertype, and full metadata with all available option definitions.

This function is useful for discovering what options a strategy accepts before constructing an instance.

Arguments

  • strategy_type::Type{<:AbstractStrategy}: The strategy type to describe

Example

julia
julia> describe(Modelers.ADNLP)
Modelers.ADNLP (strategy type)
├─ id: :adnlp
├─ supertype: AbstractNLPModeler
└─ metadata: 4 options defined
   ├─ show_time :: Bool (default: false)
   │  description: Whether to show timing information
   ├─ backend :: Symbol (default: optimized)
   │  description: AD backend used by ADNLPModels
   └─ matrix_free :: Bool (default: false)
      description: Enable matrix-free mode

See also: metadata, id, options

description [Function]

CTBase.Strategies.description Function
julia
description(_::Type{<:CTBase.Strategies.AbstractStrategy})

Return an optional description for a strategy type.

By default returns nothing (no description). Strategies may override this to provide a human-readable summary and, optionally, a reference URL. Multi-line descriptions are supported using '\n'.

Returns

  • Nothing: When no description is defined (default)

  • String: Human-readable description, optionally with URL on a second line

Example

julia
# Default: no description
description(MyStrategy)  # returns nothing

# Override with description and URL
description(::Type{<:Modelers.ADNLP}) =
    "NLP modeler using ADNLPModels.\nSee: https://jso.dev/ADNLPModels.jl"

See also: describe, AbstractStrategy

julia
description(
    parameter_type::Type{<:CTBase.Strategies.AbstractStrategyParameter}
) -> String

Get the description for a parameter type.

Every concrete parameter type should implement this method to provide a human-readable description of the parameter's purpose and behavior.

Arguments

  • parameter_type::Type{<:AbstractStrategyParameter}: The parameter type

Returns

  • String: Human-readable description of the parameter

Throws

  • Exceptions.NotImplemented: If the parameter type doesn't implement this method

Example

julia
julia> using CTBase.Strategies

julia> description(CPU)
"CPU-based computation"

julia> description(GPU)
"GPU-based computation"

See also: id, AbstractStrategyParameter

julia
description(_::Type{CTBase.Strategies.CPU}) -> String

CPU parameter description.

julia
description(_::Type{CTBase.Strategies.GPU}) -> String

GPU parameter description.

extract_id_from_method [Function]

CTBase.Strategies.extract_id_from_method Function
julia
extract_id_from_method(
    method::Tuple{Vararg{Symbol}},
    family::Type{<:CTBase.Strategies.AbstractStrategy},
    registry::CTBase.Strategies.StrategyRegistry
) -> Symbol

Extract the strategy ID for a specific family from a method tuple.

A method tuple contains multiple strategy IDs (e.g., (:collocation, :adnlp, :ipopt)). This function identifies which ID corresponds to the requested family.

Arguments

  • method::Tuple{Vararg{Symbol}}: Tuple of strategy IDs

  • family::Type{<:AbstractStrategy}: Abstract family type to search for

  • registry::StrategyRegistry: Registry containing strategy mappings

Returns

  • Symbol: The ID corresponding to the requested family

Throws

  • Exceptions.IncorrectArgument: If no ID or multiple IDs are found for the family

Example

julia
julia> method = (:collocation, :adnlp, :ipopt)

julia> extract_id_from_method(method, AbstractNLPModeler, registry)
:adnlp

julia> extract_id_from_method(method, AbstractNLPSolver, registry)
:ipopt

See also: strategy_ids

filter_options [Function]

CTBase.Strategies.filter_options Function
julia
filter_options(
    nt::NamedTuple,
    exclude::Symbol
) -> NamedTuple

Filter a NamedTuple by excluding specified keys.

Arguments

  • nt::NamedTuple: NamedTuple to filter

  • exclude::Symbol: Single key to exclude

Returns

  • NamedTuple: New NamedTuple without the excluded key

Example

julia
julia> opts = (max_iter=100, tol=1e-6, debug=true)
julia> filter_options(opts, :debug)
(max_iter = 100, tol = 1.0e-6)

See also: filter_options(::NamedTuple, ::Tuple)

julia
filter_options(
    nt::NamedTuple,
    exclude::Tuple{Vararg{Symbol}}
) -> NamedTuple

Filter a NamedTuple by excluding specified keys.

Arguments

  • nt::NamedTuple: NamedTuple to filter

  • exclude::Tuple{Vararg{Symbol}}: Tuple of keys to exclude

Returns

  • NamedTuple: New NamedTuple without the excluded keys

Example

julia
julia> opts = (max_iter=100, tol=1e-6, debug=true)
julia> filter_options(opts, (:debug, :tol))
(max_iter = 100,)

See also: filter_options(::NamedTuple, ::Symbol)

force [Function]

CTBase.Strategies.force Function

Force an option value to bypass validation.

This function is an alias for bypass and provides identical functionality. The name force may be more intuitive for users who prefer "force" semantics when bypassing validation.

Arguments

  • val: The option value to wrap

Returns

  • BypassValue: The wrapped value

Example

julia
julia> using CTBase.Strategies

julia> # Force acceptance of unknown option
julia> solver = Ipopt(
           max_iter=100, 
           custom_backend_option=force(42)  # Forces validation bypass
       )
Ipopt(options=StrategyOptions{...})

julia> # Same as bypass(42)
julia> @test force(42) == bypass(42)
true

Notes

  • force and bypass are the same function: force === bypass

  • Choose the name that best fits your mental model

  • Both functions create BypassValue wrappers

  • Use with caution for the same reasons as bypass

See also: BypassValue, bypass, route_to

format_suggestion [Function]

CTBase.Strategies.format_suggestion Function
julia
format_suggestion(s::NamedTuple) -> String

Format a suggestion entry as a human-readable string.

Example

julia
julia> format_suggestion((primary=:backend, aliases=(:adnlp_backend,), distance=1))
":backend (alias: adnlp_backend) [distance: 1]"

get_parameter_type [Function]

CTBase.Strategies.get_parameter_type Function
julia
get_parameter_type(strategy_type::Type) -> Any

Extract the parameter type from a parameterized strategy type.

For parameterized strategies like MadNLP{CPU}, this returns the parameter type CPU. For non-parameterized strategies, this returns nothing.

Arguments

  • strategy_type::Type{<:AbstractStrategy}: The strategy type to extract parameter from

Returns

  • Union{Type{<:AbstractStrategyParameter}, Nothing}: Parameter type or nothing if non-parameterized

Examples

julia
julia> get_parameter_type(MadNLP{CPU})
CPU

julia> get_parameter_type(MadNLP{GPU})
GPU

julia> get_parameter_type(Ipopt)
nothing

has_option [Function]

CTBase.Strategies.has_option Function
julia
has_option(
    strategy::CTBase.Strategies.AbstractStrategy,
    key::Symbol
) -> Any

Check if an option exists in a strategy instance.

Returns true if the option is present in the strategy's options, false otherwise. This is useful for checking if unknown options were stored in permissive mode.

Arguments

  • strategy::AbstractStrategy: The strategy instance

  • key::Symbol: The option name

Returns

  • Bool: true if the option exists

Example

julia
julia> using CTBase.Strategies

julia> strategy = MyStrategy(max_iter=200; mode=:permissive, custom_opt=123)
julia> has_option(strategy, :max_iter)
true

julia> has_option(strategy, :custom_opt)
true

julia> has_option(strategy, :nonexistent)
false

See also: option_value, option_source

id [Function]

CTBase.Strategies.id Function

Return the unique identifier for this strategy type.

Arguments

  • strategy_type::Type{<:AbstractStrategy}: The strategy type

Returns

  • Symbol: Unique identifier for the strategy

Example

julia
# For a concrete strategy type MyStrategy:
julia> id(MyStrategy)
:mystrategy

metadata [Function]

CTBase.Strategies.metadata Function

Return metadata about a strategy type.

Arguments

  • strategy_type::Type{<:AbstractStrategy}: The strategy type

Returns

  • StrategyMetadata: Option specifications and validation rules

Example

julia
# For a concrete strategy type MyStrategy:
julia> meta = metadata(MyStrategy)
julia> meta
StrategyMetadata with option definitions for max_iter, etc.

option_default [Function]

CTBase.Strategies.option_default Function
julia
option_default(
    strategy_type::Type{<:CTBase.Strategies.AbstractStrategy},
    key::Symbol
)

Get the default value for a specific option.

Returns the value that will be used if the option is not explicitly provided by the user during strategy construction.

Arguments

  • strategy_type::Type{<:AbstractStrategy}: The strategy type

  • key::Symbol: The option name

Returns

  • The default value for the option (type depends on the option)

Example

julia
julia> using CTBase.Strategies

julia> option_default(MyStrategy, :max_iter)
100

julia> option_default(MyStrategy, :tol)
1.0e-6

Throws

  • KeyError: If the option name does not exist

Notes

  • This function operates on types, not instances

  • If you have an instance, use option_default(typeof(strategy), key)

See also: option_defaults, option_type

option_defaults [Function]

CTBase.Strategies.option_defaults Function
julia
option_defaults(
    strategy_type::Type{<:CTBase.Strategies.AbstractStrategy}
)

Get all default values as a NamedTuple.

Returns a NamedTuple containing the default value for every option defined in the strategy's metadata. This is useful for resetting configurations or understanding the baseline behavior.

Arguments

  • strategy_type::Type{<:AbstractStrategy}: The strategy type

Returns

  • NamedTuple: All default values keyed by option name

Example

julia
julia> using CTBase.Strategies

julia> option_defaults(MyStrategy)
(max_iter = 100, tol = 1.0e-6)

julia> defaults = option_defaults(MyStrategy)
julia> defaults.max_iter
100

Notes

  • This function operates on types, not instances

  • If you have an instance, use option_defaults(typeof(strategy))

See also: option_default, option_names

option_description [Function]

CTBase.Strategies.option_description Function
julia
option_description(
    strategy_type::Type{<:CTBase.Strategies.AbstractStrategy},
    key::Symbol
)

Get the human-readable description for a specific option.

Returns the documentation string that explains what the option controls. This is useful for generating help messages and documentation.

Arguments

  • strategy_type::Type{<:AbstractStrategy}: The strategy type

  • key::Symbol: The option name

Returns

  • String: The option description

Example

julia
julia> using CTBase.Strategies

julia> option_description(MyStrategy, :max_iter)
"Maximum number of iterations"

julia> option_description(MyStrategy, :tol)
"Convergence tolerance"

Throws

  • KeyError: If the option name does not exist

Notes

  • This function operates on types, not instances

  • If you have an instance, use option_description(typeof(strategy), key)

See also: option_type, option_default

option_is_computed [Function]

CTBase.Strategies.option_is_computed Function
julia
option_is_computed(
    strategy::CTBase.Strategies.AbstractStrategy,
    key::Symbol
) -> Bool

Check if an option value was computed from other options.

Returns true if the option was calculated based on other option values, false if it was provided by the user or is using the default.

Arguments

  • strategy::AbstractStrategy: The strategy instance

  • key::Symbol: The option name

Returns

  • Bool: true if the option source is :computed

Example

julia
julia> using CTBase.Strategies

julia> strategy = MyStrategy()
julia> is_computed(strategy, :derived_value)
true

See also: is_user, is_default, option_source

option_is_default [Function]

CTBase.Strategies.option_is_default Function
julia
option_is_default(
    strategy::CTBase.Strategies.AbstractStrategy,
    key::Symbol
) -> Bool

Check if an option value is using its default.

Returns true if the option is using the default value from metadata, false if it was provided by the user or computed.

Arguments

  • strategy::AbstractStrategy: The strategy instance

  • key::Symbol: The option name

Returns

  • Bool: true if the option source is :default

Example

julia
julia> using CTBase.Strategies

julia> strategy = MyStrategy(max_iter=200)
julia> is_default(strategy, :max_iter)
false

julia> is_default(strategy, :tol)
true

See also: is_user, is_computed, option_source

option_is_user [Function]

CTBase.Strategies.option_is_user Function
julia
option_is_user(
    strategy::CTBase.Strategies.AbstractStrategy,
    key::Symbol
) -> Bool

Check if an option value was provided by the user.

Returns true if the option was explicitly set by the user during construction, false if it's using the default value or was computed.

Arguments

  • strategy::AbstractStrategy: The strategy instance

  • key::Symbol: The option name

Returns

  • Bool: true if the option source is :user

Example

julia
julia> using CTBase.Strategies

julia> strategy = MyStrategy(max_iter=200)
julia> is_user(strategy, :max_iter)
true

julia> is_user(strategy, :tol)
false

See also: is_default, is_computed, option_source

option_names [Function]

CTBase.Strategies.option_names Function
julia
option_names(
    strategy_type::Type{<:CTBase.Strategies.AbstractStrategy}
)

Get all option names for a strategy type.

Returns a tuple of all option names defined in the strategy's metadata. This is useful for discovering what options are available without needing to instantiate the strategy.

Arguments

  • strategy_type::Type{<:AbstractStrategy}: The strategy type to introspect

Returns

  • Tuple{Vararg{Symbol}}: Tuple of option names

Example

julia
julia> using CTBase.Strategies

julia> option_names(MyStrategy)
(:max_iter, :tol, :backend)

julia> for name in option_names(MyStrategy)
           println("Available option: ", name)
       end
Available option: max_iter
Available option: tol
Available option: backend

Notes

  • This function operates on types, not instances

  • If you have an instance, use option_names(typeof(strategy))

See also: option_type, option_description, option_default

option_source [Function]

CTBase.Strategies.option_source Function
julia
option_source(
    strategy::CTBase.Strategies.AbstractStrategy,
    key::Symbol
) -> Symbol

Get the source provenance of an option value.

Returns a symbol indicating where the option value came from:

  • :user - Explicitly provided by the user

  • :default - Using the default value from metadata

  • :computed - Calculated from other options

Arguments

  • strategy::AbstractStrategy: The strategy instance

  • key::Symbol: The option name

Returns

  • Symbol: The source provenance (:user, :default, or :computed)

Example

julia
julia> using CTBase.Strategies

julia> strategy = MyStrategy(max_iter=200)
julia> option_source(strategy, :max_iter)
:user

julia> option_source(strategy, :tol)
:default

Throws

  • KeyError: If the option name does not exist

See also: option_value, is_user, is_default

option_type [Function]

CTBase.Strategies.option_type Function
julia
option_type(
    strategy_type::Type{<:CTBase.Strategies.AbstractStrategy},
    key::Symbol
)

Get the expected type for a specific option.

Returns the Julia type that the option value must satisfy. This is useful for validation and documentation purposes.

Arguments

  • strategy_type::Type{<:AbstractStrategy}: The strategy type

  • key::Symbol: The option name

Returns

  • Type: The expected type for the option value

Example

julia
julia> using CTBase.Strategies

julia> option_type(MyStrategy, :max_iter)
Int64

julia> option_type(MyStrategy, :tol)
Float64

Throws

  • KeyError: If the option name does not exist

Notes

  • This function operates on types, not instances

  • If you have an instance, use option_type(typeof(strategy), key)

See also: option_description, option_default

option_value [Function]

CTBase.Strategies.option_value Function
julia
option_value(
    strategy::CTBase.Strategies.AbstractStrategy,
    key::Symbol
) -> Any

Get the current value of an option from a strategy instance.

Returns the effective value that the strategy is using for the specified option. This may be a user-provided value or the default value.

Arguments

  • strategy::AbstractStrategy: The strategy instance

  • key::Symbol: The option name

Returns

  • The current option value (type depends on the option)

Example

julia
julia> using CTBase.Strategies

julia> strategy = MyStrategy(max_iter=200)
julia> option_value(strategy, :max_iter)
200

julia> option_value(strategy, :tol)  # Uses default
1.0e-6

Throws

  • KeyError: If the option name does not exist

See also: option_source, options

options [Function]

CTBase.Strategies.options Function

Return the current options of a strategy as a StrategyOptions.

Arguments

  • strategy::AbstractStrategy: The strategy instance

Returns

  • StrategyOptions: Current option values with provenance tracking

Example

julia
# For a concrete strategy instance:
julia> strategy = MyStrategy(backend=:sparse)
julia> opts = options(strategy)
julia> opts
StrategyOptions with values=(backend=:sparse), sources=(backend=:user)

options_dict [Function]

CTBase.Strategies.options_dict Function
julia
options_dict(
    opts::CTBase.Strategies.StrategyOptions
) -> Dict{Symbol, Any}

Extract strategy options as a mutable Dict, ready for modification.

This method converts StrategyOptions to a Dict by unwrapping OptionValue wrappers and filtering out NotProvided values. The resulting Dict is mutable and can be modified before passing to backend solvers or model builders.

Arguments

  • opts::StrategyOptions: Strategy options to convert

Returns

  • Dict{Symbol, Any}: Mutable dictionary of option values

Example

julia
julia> using CTBase.Strategies, CTBase.Options

julia> opts = StrategyOptions(
           max_iter = OptionValue(500, :user),
           tolerance = OptionValue(1e-8, :default)
       )

julia> dict = options_dict(opts)
Dict{Symbol, Any} with 2 entries:
  :max_iter => 500
  :tolerance => 1.0e-8

julia> dict[:verbose] = true  # Modify as needed
true

Notes

  • NotProvided values are filtered out

  • Explicit nothing values are preserved

  • The returned Dict is mutable and independent from the original StrategyOptions

See also: Options.extract_raw_options, _raw_options

julia
options_dict(
    strategy::CTBase.Strategies.AbstractStrategy
) -> Dict{Symbol, Any}

Extract strategy options as a mutable Dict, ready for modification.

This is a convenience method that combines two steps into one:

  1. Getting StrategyOptions from the strategy

  2. Converting to Dict via options_dict(StrategyOptions)

Arguments

  • strategy::AbstractStrategy: Strategy instance (solver, modeler, etc.)

Returns

  • Dict{Symbol, Any}: Mutable dictionary of option values

Example

julia
julia> using CTBase

julia> solver = FakeSolver(max_iter=1000, tol=1e-8)

julia> opts = Strategies.options_dict(solver)
Dict{Symbol, Any} with 2 entries:
  :max_iter => 1000
  :tol => 1.0e-8

julia> opts[:max_iter] = 500  # Modify as needed
500

julia> solve_with_backend(nlp; opts...)

Notes

This function delegates to options_dict(StrategyOptions) for the actual conversion. It is particularly useful in solver extensions and modelers where you need to extract options and potentially modify them before passing to backend solvers or model builders.

See also: options, options_dict(::StrategyOptions)

resolve_alias [Function]

CTBase.Strategies.resolve_alias Function
julia
resolve_alias(
    meta::CTBase.Strategies.StrategyMetadata,
    key::Symbol
) -> Union{Nothing, Symbol}

Resolve an alias to its primary key name.

Searches through strategy metadata to find if a given key is either:

  1. A primary option name

  2. An alias for a primary option name

Arguments

  • meta::StrategyMetadata: Strategy metadata to search in

  • key::Symbol: Key to resolve (can be primary name or alias)

Returns

  • Union{Symbol, Nothing}: Primary key if found, nothing otherwise

Example

julia
julia> meta = metadata(MyStrategy)
julia> resolve_alias(meta, :max_iter)  # Primary name
:max_iter

julia> resolve_alias(meta, :max)  # Alias
:max_iter

julia> resolve_alias(meta, :unknown)  # Not found
nothing

See also: StrategyMetadata, OptionDefinition

route_to [Function]

CTBase.Strategies.route_to Function
julia
route_to(; kwargs...)

Create a disambiguated option value by explicitly routing it to specific strategies.

This function resolves ambiguity when the same option name exists in multiple strategies (e.g., both modeler and solver have max_iter). It creates a RoutedOption that tells the orchestration layer exactly which strategy should receive which value.

Arguments

  • kwargs...: Named arguments where keys are strategy identifiers (:solver, :modeler, etc.) and values are the option values to route to those strategies

Returns

  • RoutedOption: A routed option containing the strategy => value mappings

Throws

  • Exceptions.PreconditionError: If no strategies are provided

Example

julia
julia> using CTBase.Strategies

julia> # Single strategy
julia> route_to(solver=100)
RoutedOption((solver = 100,))

julia> # Multiple strategies with different values
julia> route_to(solver=100, modeler=50)
RoutedOption((solver = 100, modeler = 50))

julia> # Alternative positional syntax
julia> route_to(:solver, 100, :modeler, 50)
RoutedOption((solver = 100, modeler = 50))

Usage in solve()

julia
# Without disambiguation - error if max_iter exists in multiple strategies
solve(ocp, method; max_iter=100)  # ❌ Ambiguous!

# With disambiguation - explicit routing (keyword syntax)
solve(ocp, method;
    max_iter = route_to(solver=100)              # Only solver gets 100
)

solve(ocp, method;
    max_iter = route_to(solver=100, modeler=50)  # Different values for each
)

# With disambiguation - explicit routing (positional syntax)
solve(ocp, method;
    max_iter = route_to(:solver, 100, :modeler, 50)  # Different values for each
)

Notes

  • Strategy identifiers must match the actual strategy IDs in your method tuple

  • You can route to one or multiple strategies in a single call

  • Alternative positional syntax: route_to(:solver, 100, :modeler, 50)

  • Both syntaxes are equivalent; choose based on preference

  • This is the recommended way to disambiguate options

  • The orchestration layer will validate that the strategy IDs exist

See also: RoutedOption, route_all_options

julia
route_to(args...)

Create a disambiguated option value using positional arguments.

This is an alternative syntax to the keyword argument version. Accepts alternating strategy identifier (Symbol) and value pairs.

Arguments

  • args::Vararg{Any}: Alternating strategy_id (Symbol) and value pairs. Must have an even number of arguments. Odd-numbered arguments must be Symbols.

Returns

  • RoutedOption: A routed option containing the strategy => value mappings

Throws

  • Exceptions.PreconditionError: If no arguments provided, odd number of arguments, or odd-numbered arguments are not Symbols

Example

julia
julia> using CTBase.Strategies

julia> # Single strategy
julia> route_to(:solver, 100)
RoutedOption((solver = 100,))

julia> # Multiple strategies
julia> route_to(:solver, 100, :modeler, 50)
RoutedOption((solver = 100, modeler = 50))

Notes

  • This is equivalent to the keyword syntax: route_to(solver=100, modeler=50)

  • Strategy identifiers must be Symbols (e.g., :solver, not "solver")

  • The number of arguments must be even (pairs of Symbol-value)

See also: route_to(; kwargs...), RoutedOption

strategy_ids [Function]

CTBase.Strategies.strategy_ids Function
julia
strategy_ids(
    family::Type{<:CTBase.Strategies.AbstractStrategy},
    registry::CTBase.Strategies.StrategyRegistry
) -> Tuple{Vararg{Symbol}}

Get all strategy IDs for a given family.

Returns a tuple of symbolic identifiers for all strategies registered under the specified family type. The order matches the registration order.

Arguments

  • family::Type{<:AbstractStrategy}: The abstract family type

  • registry::StrategyRegistry: The registry to query

Returns

  • Tuple{Vararg{Symbol}}: Tuple of strategy IDs in registration order

Example

julia
julia> using CTBase.Strategies

julia> ids = strategy_ids(AbstractNLPModeler, registry)
(:adnlp, :exa)

julia> for strategy_id in ids
           println("Available: ", strategy_id)
       end
Available: adnlp
Available: exa

Throws

  • ErrorException: If the family is not found in the registry

See also: type_from_id, create_registry

suggest_options [Function]

CTBase.Strategies.suggest_options Function
julia
suggest_options(
    key::Symbol,
    strategy_type::Type{<:CTBase.Strategies.AbstractStrategy};
    max_suggestions
)

Suggest similar option names for an unknown key using Levenshtein distance.

For each option, the distance is the minimum over the primary name and all its aliases. Results are grouped by primary option name and sorted by this minimum distance.

Arguments

  • key::Symbol: Unknown key to find suggestions for

  • strategy_type::Type{<:AbstractStrategy}: Strategy type to search in

  • max_suggestions::Int=3: Maximum number of suggestions to return

Returns

  • Vector{@NamedTuple{primary::Symbol, aliases::Tuple{Vararg{Symbol}}, distance::Int}}: Suggested options sorted by distance (closest first), each with primary name, aliases, and distance.

Example

julia
julia> suggest_options(:max_it, MyStrategy)
1-element Vector{...}:
 (primary = :max_iter, aliases = (), distance = 2)

julia> suggest_options(:adnlp_backen, MyStrategy)
1-element Vector{...}:
 (primary = :backend, aliases = (:adnlp_backend,), distance = 1)

Note

The distance of an option to the key is min(dist(key, primary), dist(key, alias1), ...). This ensures that options with a close alias are suggested even if the primary name is far.

See also: resolve_alias, levenshtein_distance

julia
suggest_options(
    key::Symbol,
    meta::CTBase.Strategies.StrategyMetadata;
    max_suggestions
) -> Vector{@NamedTuple{primary::Symbol, aliases::Tuple{Vararg{Symbol}}, distance::Int64}}

Suggest similar option names from a StrategyMetadata using Levenshtein distance.

See suggest_options(::Symbol, ::Type{<:AbstractStrategy}) for details.

type_from_id [Function]

CTBase.Strategies.type_from_id Function
julia
type_from_id(
    strategy_id::Symbol,
    family::Type{<:CTBase.Strategies.AbstractStrategy},
    registry::CTBase.Strategies.StrategyRegistry;
    parameter
) -> Type

Lookup a strategy type from its ID within a family.

Searches the registry for a strategy with the given symbolic identifier within the specified family. This is the core lookup mechanism used by the builder functions to convert symbolic descriptions to concrete types.

Arguments

  • strategy_id::Symbol: The symbolic identifier to look up

  • family::Type{<:AbstractStrategy}: The family to search within

  • registry::StrategyRegistry: The registry to query

Returns

  • Type{<:AbstractStrategy}: The concrete strategy type matching the ID

Example

julia
julia> using CTBase.Strategies

julia> T = type_from_id(:adnlp, AbstractNLPModeler, registry)
Modelers.ADNLP

julia> id(T)
:adnlp

Throws

  • Exceptions.IncorrectArgument: If the family is not found in the registry

  • Exceptions.IncorrectArgument: If the ID is not found within the family (includes suggestions)

See also: strategy_ids, build_strategy