From a8c410eb3bf26ad7b0e6f22aab08a7384b645d50 Mon Sep 17 00:00:00 2001 From: Olivier Cots Date: Tue, 23 Jun 2026 14:54:36 +0200 Subject: [PATCH 1/6] docs: simplify nav configuration in Vitepress config and document in migration guide --- docs/MIGRATION.md | 28 ++++++++++++++++++++++++++++ docs/src/.vitepress/config.mts | 10 ++-------- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/docs/MIGRATION.md b/docs/MIGRATION.md index 385b3545..ece14f44 100644 --- a/docs/MIGRATION.md +++ b/docs/MIGRATION.md @@ -153,6 +153,34 @@ let ctOutDir = '' And reference them in `head` using `${baseTemp.base}assets/...` instead of the remote URLs. +#### Simplify nav configuration + +The generated `docs/src/.vitepress/config.mts` includes a placeholder for the navigation that spreads from `navTemp.nav`. Replace it with a direct array definition: + +Replace: + +```typescript +const navTemp = { + nav: 'REPLACE_ME_DOCUMENTER_VITEPRESS', +} + +const nav = [ + ...navTemp.nav, + { + component: 'VersionPicker' + } +] +``` + +With: + +```typescript +const nav = [ + { text: 'Home', link: '/index' }, + {component: 'VersionPicker'} +] +``` + ### 6. Install npm dependencies ```bash diff --git a/docs/src/.vitepress/config.mts b/docs/src/.vitepress/config.mts index 3e64b2d8..1b30e2f2 100644 --- a/docs/src/.vitepress/config.mts +++ b/docs/src/.vitepress/config.mts @@ -17,15 +17,9 @@ const baseTemp = { base: 'REPLACE_ME_DOCUMENTER_VITEPRESS',// TODO: replace this in makedocs! } -const navTemp = { - nav: 'REPLACE_ME_DOCUMENTER_VITEPRESS', -} - const nav = [ - ...navTemp.nav, - { - component: 'VersionPicker' - } + { text: 'Home', link: '/index' }, + {component: 'VersionPicker'} ] // https://vitepress.dev/reference/site-config From 2512afe5f0938abe7467b3f45739c69e52b821dc Mon Sep 17 00:00:00 2001 From: Olivier Cots Date: Tue, 23 Jun 2026 15:46:56 +0200 Subject: [PATCH 2/6] Add CTBase.Traits submodule (moved from CTFlows) New `CTBase.Traits` submodule providing the trait system shared across the control-toolbox ecosystem: time dependence (`TimeDependence`/`Autonomous`/ `NonAutonomous`, now defined natively here instead of in CTModels), variable dependence (`Fixed`/`NonFixed`), integration mode, dynamics, mutability, AD and variable-costate traits, plus the generic predicates (`is_autonomous`, `is_variable`, ...) with their `::Any` fallbacks and trait-contract dispatch. Registered in CTBase.jl after Exceptions. Bumps version to 0.22.0-beta. Co-Authored-By: Claude Opus 4.8 --- Project.toml | 2 +- src/CTBase.jl | 4 + src/Traits/Traits.jl | 67 ++++++++++ src/Traits/abstract.jl | 51 ++++++++ src/Traits/ad.jl | 127 +++++++++++++++++++ src/Traits/dynamics.jl | 121 ++++++++++++++++++ src/Traits/helpers.jl | 26 ++++ src/Traits/mode.jl | 96 +++++++++++++++ src/Traits/mutability.jl | 180 +++++++++++++++++++++++++++ src/Traits/time_dependence.jl | 151 +++++++++++++++++++++++ src/Traits/variable_costate.jl | 126 +++++++++++++++++++ src/Traits/variable_dependence.jl | 196 ++++++++++++++++++++++++++++++ 12 files changed, 1146 insertions(+), 1 deletion(-) create mode 100644 src/Traits/Traits.jl create mode 100644 src/Traits/abstract.jl create mode 100644 src/Traits/ad.jl create mode 100644 src/Traits/dynamics.jl create mode 100644 src/Traits/helpers.jl create mode 100644 src/Traits/mode.jl create mode 100644 src/Traits/mutability.jl create mode 100644 src/Traits/time_dependence.jl create mode 100644 src/Traits/variable_costate.jl create mode 100644 src/Traits/variable_dependence.jl diff --git a/Project.toml b/Project.toml index fd0b378c..ec82be17 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "CTBase" uuid = "54762871-cc72-4466-b8e8-f6c8b58076cd" -version = "0.21.1-beta" +version = "0.22.0-beta" authors = ["Olivier Cots ", "Jean-Baptiste Caillau "] [deps] diff --git a/src/CTBase.jl b/src/CTBase.jl index 3832490a..61e7e79a 100644 --- a/src/CTBase.jl +++ b/src/CTBase.jl @@ -32,6 +32,10 @@ using .Strategies include(joinpath(@__DIR__, "Orchestration", "Orchestration.jl")) using .Orchestration +# Traits module - trait types and trait-based dispatch (moved from CTFlows) +include(joinpath(@__DIR__, "Traits", "Traits.jl")) +using .Traits + # Unicode module - Unicode character utilities include(joinpath(@__DIR__, "Unicode", "Unicode.jl")) using .Unicode diff --git a/src/Traits/Traits.jl b/src/Traits/Traits.jl new file mode 100644 index 00000000..dacb3e1c --- /dev/null +++ b/src/Traits/Traits.jl @@ -0,0 +1,67 @@ +""" + Traits + +Trait types and trait-based dispatch shared across the control-toolbox ecosystem. + +This module provides the trait system used for compile-time dispatch on: +- Time dependence: [`Autonomous`](@ref), [`NonAutonomous`](@ref) +- Variable dependence: [`Fixed`](@ref), [`NonFixed`](@ref) +- Integration mode: [`EndPointMode`](@ref), [`TrajectoryMode`](@ref) +- Dynamics type: [`StateDynamics`](@ref), [`HamiltonianDynamics`](@ref), [`AugmentedHamiltonianDynamics`](@ref) +- Mutability: [`InPlace`](@ref), [`OutOfPlace`](@ref) +- Automatic differentiation: [`WithAD`](@ref), [`WithoutAD`](@ref) +- Variable costate capability: [`SupportsVariableCostate`](@ref), [`NoVariableCostate`](@ref) + +Traits are used as type parameters in configuration types, vector fields, and systems +to enable static dispatch without runtime type checks. + +The time-dependence trait types (`TimeDependence`, `Autonomous`, `NonAutonomous`) +historically lived in `CTModels.Components`; they are now defined here so the whole +ecosystem shares a single set of types (CTModels consumes them from here). +""" +module Traits + +# ============================================================================== +# External package imports +# ============================================================================== + +import DocStringExtensions: TYPEDEF, TYPEDSIGNATURES +import CTBase.Exceptions + +# ============================================================================== +# Includes +# ============================================================================== + +include(joinpath(@__DIR__, "helpers.jl")) +include(joinpath(@__DIR__, "abstract.jl")) +include(joinpath(@__DIR__, "mode.jl")) +include(joinpath(@__DIR__, "dynamics.jl")) +include(joinpath(@__DIR__, "ad.jl")) +include(joinpath(@__DIR__, "variable_costate.jl")) +include(joinpath(@__DIR__, "mutability.jl")) +include(joinpath(@__DIR__, "time_dependence.jl")) +include(joinpath(@__DIR__, "variable_dependence.jl")) + +# ============================================================================== +# Module exports +# ============================================================================== + +export AbstractTrait +export AbstractModeTrait, AbstractDynamicsTrait +export AbstractMutabilityTrait +export AbstractADTrait +export AbstractVariableCostateCapability +export TimeDependence, Autonomous, NonAutonomous +export EndPointMode, TrajectoryMode +export StateDynamics, HamiltonianDynamics, AugmentedHamiltonianDynamics +export InPlace, OutOfPlace +export WithAD, WithoutAD +export SupportsVariableCostate, NoVariableCostate +export VariableDependence, Fixed, NonFixed +export ad_trait, variable_costate_trait, dynamics_trait +export is_inplace, is_outofplace +export is_autonomous, is_nonautonomous, is_variable, is_nonvariable, has_variable +export has_time_dependence_trait, time_dependence, has_mutability_trait, mutability +export has_variable_dependence_trait, variable_dependence + +end # module Traits diff --git a/src/Traits/abstract.jl b/src/Traits/abstract.jl new file mode 100644 index 00000000..d405f927 --- /dev/null +++ b/src/Traits/abstract.jl @@ -0,0 +1,51 @@ +""" +$(TYPEDEF) + +Abstract base type for trait markers in CTFlows. + +Traits are empty marker types used as type parameters to encode configuration +properties at compile time. Unlike tags (which mark extension implementations), +traits encode semantic properties of the configuration itself (e.g., integration +mode, content type, mutability). + +# Trait Pattern + +Traits are used as type parameters in abstract configuration types to enable +compile-time dispatch without runtime type checks. For example, `AbstractConfig` +uses `EndPointMode` vs `TrajectoryMode` to distinguish integration modes, and +`StateDynamics` vs `HamiltonianDynamics` to distinguish dynamics types. + +All concrete trait types are empty structs with no fields, making them zero-cost +at runtime. + +# Interface Requirements + +Concrete trait subtypes should: +- Be empty structs with no fields (pure markers) +- Subtype an intermediate abstract trait category (e.g., `AbstractModeTrait`) +- Be used as type parameters in configuration types + +# Example +\`\`\`julia-repl +julia> using CTBase.Traits + +julia> EndPointMode <: Traits.AbstractTrait +true + +julia> EndPointMode <: Traits.AbstractModeTrait +true + +julia> # Used as type parameters in configs: +julia> StateEndPointConfig <: CTFlows.Configs.AbstractConfig{<:Any, EndPointMode, StateDynamics} +true +\`\`\` + +# Notes +- Traits are distinct from tags: tags mark extension implementations (e.g., `SciMLTag`), + while traits encode configuration semantics (e.g., `EndPointMode`) +- All trait types have zero runtime overhead (empty structs) +- The trait pattern enables static dispatch on configuration properties + +See also: [`CTBase.Traits.VariableDependence`](@ref), [`CTBase.Traits.AbstractModeTrait`](@ref), [`CTBase.Traits.AbstractDynamicsTrait`](@ref), [`CTBase.Traits.AbstractMutabilityTrait`](@ref). +""" +abstract type AbstractTrait end diff --git a/src/Traits/ad.jl b/src/Traits/ad.jl new file mode 100644 index 00000000..2e1a1f60 --- /dev/null +++ b/src/Traits/ad.jl @@ -0,0 +1,127 @@ +""" +$(TYPEDEF) + +Abstract base type for automatic differentiation capability traits. + +AD traits encode whether a system supports automatic differentiation for gradient +computation. This distinction enables compile-time dispatch for cache preparation, +derivative computation, and other AD-related operations. + +Common use cases include: +- Hamiltonian systems: distinguishing between scalar Hamiltonians with AD backends + and pre-computed Hamiltonian vector fields +- General optimization: marking systems that can compute gradients via AD vs. those + with manual derivative implementations +- Cache preparation: enabling static dispatch for AD-specific cache initialization + +# Example +\`\`\`julia-repl +julia> using CTBase.Traits + +julia> WithAD() isa Traits.AbstractADTrait +true + +julia> WithoutAD() isa Traits.AbstractADTrait +true +\`\`\` + +# Notes +- AD traits are used as type parameters in system types to enable static dispatch +- `WithAD` indicates the system carries differentiable functions and an AD backend +- `WithoutAD` indicates the system uses pre-computed derivatives or manual implementations +- The specific meaning depends on the system type and context + +See also: [`CTBase.Traits.WithAD`](@ref), [`CTBase.Traits.WithoutAD`](@ref), [`CTBase.Core.AbstractCache`](@ref). +""" +abstract type AbstractADTrait <: AbstractTrait end + +""" +$(TYPEDEF) + +Trait for systems with automatic differentiation support. + +Indicates that a system carries differentiable functions and an AD backend, +enabling automatic computation of derivatives. Such systems typically require +cache preparation before operations that need gradients or Jacobians. + +Common use cases include: +- Hamiltonian systems: scalar Hamiltonians where the vector field is computed via AD +- Optimization: objective functions where gradients are computed via AD +- General systems: any differentiable function that benefits from automatic gradient computation + +# Example +\`\`\`julia-repl +julia> using CTBase.Traits + +julia> with = WithAD() +WithAD() + +julia> with isa Traits.AbstractADTrait +true +\`\`\` + +# Notes +- Used as a type parameter in system types to enable AD-based derivative computation +- Systems with `WithAD` typically require cache preparation via the backend's `prepare_cache` method +- The cache is passed through parameters during integration or evaluation +- The specific operations enabled depend on the system type and AD backend + +See also: [`CTBase.Traits.AbstractADTrait`](@ref), [`CTBase.Traits.WithoutAD`](@ref), [`CTBase.Core.AbstractCache`](@ref). +""" +struct WithAD <: AbstractADTrait end # system carries H + AD backend + +""" +$(TYPEDEF) + +Trait for systems without automatic differentiation support. + +Indicates that a system uses pre-computed derivatives or manual implementations, +without requiring AD or cache preparation. This is the traditional mode where +derivatives are provided explicitly by the user or computed offline. + +Common use cases include: +- Hamiltonian systems: pre-computed Hamiltonian vector fields provided manually +- Optimization: manually implemented gradient functions +- General systems: any system where derivatives are known analytically or computed externally + +# Example +\`\`\`julia-repl +julia> using CTBase.Traits + +julia> without = WithoutAD() +WithoutAD() + +julia> without isa Traits.AbstractADTrait +true +\`\`\` + +# Notes +- Used as a type parameter in system types for derivative-based systems without AD +- No cache preparation is required for `WithoutAD` systems +- This is the default mode for systems with pre-computed derivatives +- The specific derivative implementations depend on the system type + +See also: [`CTBase.Traits.AbstractADTrait`](@ref), [`CTBase.Traits.WithAD`](@ref). +""" +struct WithoutAD <: AbstractADTrait end # system carries HVF directly + +""" +$(TYPEDSIGNATURES) + +Return the automatic differentiation capability trait of a system or flow. + +# Arguments +- `obj`: Any object (default implementation returns `WithoutAD`). + +# Returns +- `Type{<:AbstractADTrait}`: The AD capability trait, either `WithAD` or `WithoutAD`. + +# Notes +- Default implementation returns `WithoutAD` for all objects +- Specialized implementations on system types return the appropriate trait based on the system's AD support +- Used for dispatch in cache preparation, derivative computation, and augmented integration +- The specific operations enabled by the trait depend on the system type + +See also: [`CTBase.Traits.AbstractADTrait`](@ref), [`CTBase.Traits.WithAD`](@ref), [`CTBase.Traits.WithoutAD`](@ref). +""" +ad_trait(::Any) = WithoutAD diff --git a/src/Traits/dynamics.jl b/src/Traits/dynamics.jl new file mode 100644 index 00000000..deb90c08 --- /dev/null +++ b/src/Traits/dynamics.jl @@ -0,0 +1,121 @@ +""" +$(TYPEDEF) + +Abstract base type for dynamics traits (State vs Hamiltonian). + +Dynamics traits encode the dynamics type in configuration types, distinguishing +between state-only configurations (no costate) and Hamiltonian configurations +(state + costate). + +# Example +\`\`\`julia-repl +julia> using CTBase.Traits + +julia> StateDynamics <: Traits.AbstractDynamicsTrait +true + +julia> HamiltonianDynamics <: Traits.AbstractDynamicsTrait +true + +julia> # Used in configuration type parameters: +julia> StateEndPointConfig <: CTFlows.Configs.AbstractConfig{<:Any, <:Traits.AbstractModeTrait, StateDynamics} +true +\`\`\` + +# Notes +- Dynamics traits are used as the third type parameter in `AbstractConfigWithMaC` +- State dynamics indicates configurations with only state variables (no costate) +- Hamiltonian dynamics indicates configurations with both state and costate variables + +See also: [`CTBase.Traits.StateDynamics`](@ref), [`CTBase.Traits.HamiltonianDynamics`](@ref), [`CTFlows.Configs.AbstractConfig`](@ref). +""" +abstract type AbstractDynamicsTrait <: AbstractTrait end + +""" +$(TYPEDEF) + +Trait for state dynamics (no costate). + +Used as a type parameter in `AbstractConfig` to indicate state-only configurations, +which contain only state variables without associated costate variables. + +# Example +\`\`\`julia-repl +julia> using CTBase.Traits + +julia> st = StateDynamics() +StateDynamics() + +julia> st isa Traits.AbstractDynamicsTrait +true + +julia> # Used in state-only configurations: +julia> StateEndPointConfig <: CTFlows.Configs.AbstractConfig{<:Any, <:Traits.AbstractModeTrait, StateDynamics} +true +\`\`\` + +# Notes +- State configurations store only `x0` (initial state) +- The `initial_costate` accessor throws a `PreconditionError` for state configurations +- This mode is suitable for standard ODE integration without adjoint variables + +See also: [`CTBase.Traits.HamiltonianDynamics`](@ref), [`CTBase.Traits.AbstractDynamicsTrait`](@ref), [`CTFlows.Configs.StateEndPointConfig`](@ref). +""" +struct StateDynamics <: AbstractDynamicsTrait end + +""" +$(TYPEDEF) + +Trait for Hamiltonian dynamics (state + costate). + +Used as a type parameter in `AbstractConfig` to indicate Hamiltonian configurations, +which contain both state variables and associated costate (adjoint) variables. + +# Example +\`\`\`julia-repl +julia> using CTBase.Traits + +julia> ham = HamiltonianDynamics() +HamiltonianDynamics() + +julia> ham isa Traits.AbstractDynamicsTrait +true + +julia> # Used in Hamiltonian configurations: +julia> HamiltonianEndPointConfig <: CTFlows.Configs.AbstractConfig{<:Any, <:Traits.AbstractModeTrait, HamiltonianDynamics} +true +\`\`\` + +# Notes +- Hamiltonian configurations store both `x0` (initial state) and `p0` (initial costate) +- The `initial_condition` accessor returns `vcat(x0, p0)` for Hamiltonian configurations +- This mode is suitable for optimal control problems with Pontryagin's maximum principle + +See also: [`CTBase.Traits.StateDynamics`](@ref), [`CTBase.Traits.AbstractDynamicsTrait`](@ref), [`CTFlows.Configs.HamiltonianEndPointConfig`](@ref). +""" +struct HamiltonianDynamics <: AbstractDynamicsTrait end + +""" +$(TYPEDEF) + +Trait marker for augmented Hamiltonian dynamics, where the Hamiltonian includes an augmented variable (e.g., a parameter or control variable) in addition to state and costate variables. + +# Notes +- Used in conjunction with [`CTFlows.Configs.AbstractAugmentedHamiltonianConfig`](@ref) to specify that a configuration is for an augmented Hamiltonian system. +- Subtypes [`CTBase.Traits.AbstractDynamicsTrait`](@ref). +- Used to distinguish augmented Hamiltonian systems from standard Hamiltonian systems in trait-based dispatch. + +See also: [`CTBase.Traits.HamiltonianDynamics`](@ref), [`CTFlows.Configs.AbstractAugmentedHamiltonianConfig`](@ref), [`CTBase.Traits.AbstractDynamicsTrait`](@ref). +""" +struct AugmentedHamiltonianDynamics <: AbstractDynamicsTrait end + +""" + dynamics_trait(x) + +Return the dynamics trait of `x`. + +Methods are defined on concrete types in `Systems` and `Configs`. + +See also: [`CTBase.Traits.AbstractDynamicsTrait`](@ref), [`CTBase.Traits.StateDynamics`](@ref), [`CTBase.Traits.HamiltonianDynamics`](@ref). +""" +function dynamics_trait end diff --git a/src/Traits/helpers.jl b/src/Traits/helpers.jl new file mode 100644 index 00000000..1b878697 --- /dev/null +++ b/src/Traits/helpers.jl @@ -0,0 +1,26 @@ +""" + _caller_function_name() -> Symbol + +Return the name of the calling function by inspecting the stacktrace. + +This is used to provide better error messages in trait check functions +without requiring an explicit `source_method` argument. + +# Returns +- `Symbol`: The name of the calling function, or `:unknown` if it cannot be determined. +""" +function _caller_function_name() + stack = stacktrace() + for frame in stack + func_name = frame.func + func_str = string(func_name) + if func_str != "_caller_function_name" && + !startswith(func_str, "#") && + func_str != "has_time_dependence_trait" && + func_str != "has_variable_dependence_trait" && + func_str != "has_mutability_trait" + return func_name + end + end + return :unknown +end diff --git a/src/Traits/mode.jl b/src/Traits/mode.jl new file mode 100644 index 00000000..f40d350c --- /dev/null +++ b/src/Traits/mode.jl @@ -0,0 +1,96 @@ +""" +$(TYPEDEF) + +Abstract base type for mode traits (Point vs Trajectory). + +Mode traits encode the integration mode in configuration types, distinguishing +between point-to-point integration (single endpoint evaluation) and trajectory +integration (full time evolution). + +# Example +\`\`\`julia-repl +julia> using CTBase.Traits + +julia> EndPointMode <: Traits.AbstractModeTrait +true + +julia> TrajectoryMode <: Traits.AbstractModeTrait +true + +julia> # Used in configuration type parameters: +julia> StateEndPointConfig <: CTFlows.Configs.AbstractConfig{<:Any, EndPointMode, <:Traits.AbstractDynamicsTrait} +true +\`\`\` + +# Notes +- Mode traits are used as the second type parameter in `AbstractConfigWithMaC` +- Point mode indicates integration from a single initial condition to a specific final time +- Trajectory mode indicates integration over a continuous time interval + +See also: [`CTBase.Traits.EndPointMode`](@ref), [`CTBase.Traits.TrajectoryMode`](@ref), [`CTFlows.Configs.AbstractConfig`](@ref). +""" +abstract type AbstractModeTrait <: AbstractTrait end + +""" +$(TYPEDEF) + +Trait for point integration mode (single endpoint evaluation). + +Used as a type parameter in `AbstractConfig` to indicate point integration, +which computes the solution at a specific final time from a single initial condition. + +# Example +\`\`\`julia-repl +julia> using CTBase.Traits + +julia> pt = EndPointMode() +EndPointMode() + +julia> pt isa Traits.AbstractModeTrait +true + +julia> # Used in point-to-point configurations: +julia> StateEndPointConfig <: CTFlows.Configs.AbstractConfig{<:Any, EndPointMode, <:Traits.AbstractDynamicsTrait} +true +\`\`\` + +# Notes +- Point mode configurations store `t0` and `tf` as separate fields +- This mode is suitable for boundary value problems and shooting methods +- The `tspan` accessor returns `(c.t0, c.tf)` for point configurations + +See also: [`CTBase.Traits.TrajectoryMode`](@ref), [`CTBase.Traits.AbstractModeTrait`](@ref), [`CTFlows.Configs.StateEndPointConfig`](@ref). +""" +struct EndPointMode <: AbstractModeTrait end + +""" +$(TYPEDEF) + +Trait for trajectory integration mode (full time evolution). + +Used as a type parameter in `AbstractConfig` to indicate trajectory integration, +which computes the full solution trajectory over a continuous time interval. + +# Example +\`\`\`julia-repl +julia> using CTBase.Traits + +julia> traj = TrajectoryMode() +TrajectoryMode() + +julia> traj isa Traits.AbstractModeTrait +true + +julia> # Used in trajectory configurations: +julia> StateTrajectoryConfig <: CTFlows.Configs.AbstractConfig{<:Any, TrajectoryMode, <:Traits.AbstractDynamicsTrait} +true +\`\`\` + +# Notes +- Trajectory mode configurations store `tspan` as a tuple field +- This mode is suitable for generating full time evolution and visualization +- The `tspan` accessor returns `c.tspan` directly for trajectory configurations + +See also: [`CTBase.Traits.EndPointMode`](@ref), [`CTBase.Traits.AbstractModeTrait`](@ref), [`CTFlows.Configs.StateTrajectoryConfig`](@ref). +""" +struct TrajectoryMode <: AbstractModeTrait end diff --git a/src/Traits/mutability.jl b/src/Traits/mutability.jl new file mode 100644 index 00000000..89bef4f5 --- /dev/null +++ b/src/Traits/mutability.jl @@ -0,0 +1,180 @@ +""" +$(TYPEDEF) + +Abstract trait for mutability characteristics of function evaluation. + +Distinguishes between in-place functions (which modify a pre-allocated buffer) +and out-of-place functions (which allocate and return new results). + +Subtypes must implement: +- `InPlace`: For functions that write to a mutable buffer +- `OutOfPlace`: For functions that return newly allocated results + +# Example +\`\`\`julia-repl +julia> using CTBase.Traits + +julia> InPlace() isa AbstractMutabilityTrait +true + +julia> OutOfPlace() isa AbstractMutabilityTrait +true +\`\`\` + +See also: [`CTBase.Traits.InPlace`](@ref), [`CTBase.Traits.OutOfPlace`](@ref). +""" +abstract type AbstractMutabilityTrait <: AbstractTrait end + +""" +$(TYPEDEF) + +Trait for in-place function evaluation. + +Indicates that a function modifies a pre-allocated buffer passed as an argument, +rather than allocating and returning a new result. This pattern is used for +performance-critical code where avoiding allocations is important. + +# Example +\`\`\`julia-repl +julia> using CTBase.Traits + +julia> ip = InPlace() +InPlace() + +julia> ip isa AbstractMutabilityTrait +true +\`\`\` + +See also: [`CTBase.Traits.AbstractMutabilityTrait`](@ref), [`CTBase.Traits.OutOfPlace`](@ref). +""" +struct InPlace <: AbstractMutabilityTrait end + +""" +$(TYPEDEF) + +Trait for out-of-place function evaluation. + +Indicates that a function allocates and returns a new result, rather than +modifying a pre-allocated buffer. This is the default pattern in Julia and +is suitable for most use cases. + +# Example +\`\`\`julia-repl +julia> using CTBase.Traits + +julia> oop = OutOfPlace() +OutOfPlace() + +julia> oop isa AbstractMutabilityTrait +true +\`\`\` + +See also: [`CTBase.Traits.AbstractMutabilityTrait`](@ref), [`CTBase.Traits.InPlace`](@ref). +""" +struct OutOfPlace <: AbstractMutabilityTrait end + +""" +$(TYPEDSIGNATURES) + +Check if the object has the mutability trait. + +This fallback method throws an error indicating the object does not support +mutability queries. Concrete types that have the trait should implement +`has_mutability_trait(obj::MyType) = true`. + +The calling function name is automatically detected from the stacktrace +for better error messages. + +# Arguments +- `obj::Any`: The object to check. + +# Throws +- [`CTBase.Exceptions.IncorrectArgument`](@extref): Always, indicating the object does not have the trait. + +See also: [`CTBase.Traits.AbstractMutabilityTrait`](@ref), [`CTBase.Traits.mutability`](@ref). +""" +function has_mutability_trait(obj::Any) + source_method = _caller_function_name() + throw(Exceptions.IncorrectArgument( + "Cannot call $(source_method) on object of type $(typeof(obj)): no mutability trait"; + suggestion = "Implement has_mutability_trait(obj::$(typeof(obj))) = true and mutability(obj::$(typeof(obj))) to enable mutability trait support.", + context = "Mutability trait not available", + )) +end + +""" +$(TYPEDSIGNATURES) + +Return the mutability trait value for the object. + +This fallback method throws an error indicating the method is not implemented. +Concrete types that have the trait should implement `mutability(obj::MyType)` +to return the specific trait value (`InPlace` or `OutOfPlace`). + +# Arguments +- `obj::Any`: The object to query. + +# Throws +- [`CTBase.Exceptions.NotImplemented`](@extref): Always, indicating the method must be implemented. + +See also: [`CTBase.Traits.AbstractMutabilityTrait`](@ref), [`CTBase.Traits.has_mutability_trait`](@ref). +""" +function mutability(obj::Any) + has_mutability_trait(obj) + throw(Exceptions.NotImplemented( + "mutability not implemented for $(typeof(obj))"; + required_method = "mutability(obj::$(typeof(obj)))", + suggestion = "Implement mutability for your concrete object type to return the specific mutability trait (InPlace or OutOfPlace).", + context = "Mutability trait - required method implementation", + )) +end + +""" +$(TYPEDSIGNATURES) + +Return true if the object uses in-place function evaluation. + +Checks that the object has the mutability trait, then returns true +if `mutability(obj)` is `InPlace`. + +# Arguments +- `obj::Any`: The object to check. + +# Returns +- `Bool`: true if the object uses in-place evaluation. + +# Throws +- [`CTBase.Exceptions.IncorrectArgument`](@extref): If the object does not support mutability queries. +- [`CTBase.Exceptions.NotImplemented`](@extref): If `mutability` is not implemented for the object type. + +See also: [`CTBase.Traits.AbstractMutabilityTrait`](@ref), [`CTBase.Traits.mutability`](@ref). +""" +function is_inplace(obj::Any) + has_mutability_trait(obj) + return mutability(obj) === InPlace +end + +""" +$(TYPEDSIGNATURES) + +Return true if the object uses out-of-place function evaluation. + +Checks that the object has the mutability trait, then returns true +if `mutability(obj)` is `OutOfPlace`. + +# Arguments +- `obj::Any`: The object to check. + +# Returns +- `Bool`: true if the object uses out-of-place evaluation. + +# Throws +- [`CTBase.Exceptions.IncorrectArgument`](@extref): If the object does not support mutability queries. +- [`CTBase.Exceptions.NotImplemented`](@extref): If `mutability` is not implemented for the object type. + +See also: [`CTBase.Traits.AbstractMutabilityTrait`](@ref), [`CTBase.Traits.mutability`](@ref). +""" +function is_outofplace(obj::Any) + has_mutability_trait(obj) + return mutability(obj) === OutOfPlace +end diff --git a/src/Traits/time_dependence.jl b/src/Traits/time_dependence.jl new file mode 100644 index 00000000..311a1d69 --- /dev/null +++ b/src/Traits/time_dependence.jl @@ -0,0 +1,151 @@ +# ============================================================================= +# Time-dependence trait types +# +# These were historically defined in CTModels.Components; they now live here so +# the whole ecosystem (CTModels, CTFlows, ...) shares a single set of types. +# Kept as abstract types (used as the `Model{TD,...}` type parameter in CTModels). +# ============================================================================= + +""" +$(TYPEDEF) + +Abstract base type representing time dependence of an object (e.g. an optimal +control problem, a vector field, a Hamiltonian). + +Used as a type parameter to distinguish between autonomous and non-autonomous +objects at the type level, enabling dispatch and compile-time optimisations. + +See also: [`Autonomous`](@ref), [`NonAutonomous`](@ref). +""" +abstract type TimeDependence end + +""" +$(TYPEDEF) + +Type tag indicating that the dynamics and other functions do not explicitly +depend on time. For autonomous systems, the dynamics have the form `ẋ = f(x, u)` +rather than `ẋ = f(t, x, u)`. + +See also: [`TimeDependence`](@ref), [`NonAutonomous`](@ref). +""" +abstract type Autonomous <: TimeDependence end + +""" +$(TYPEDEF) + +Type tag indicating that the dynamics and other functions explicitly depend on +time. For non-autonomous systems, the dynamics have the form `ẋ = f(t, x, u)`. + +See also: [`TimeDependence`](@ref), [`Autonomous`](@ref). +""" +abstract type NonAutonomous <: TimeDependence end + +# ============================================================================= +# Time-dependence trait contract +# ============================================================================= + +""" +$(TYPEDSIGNATURES) + +Check if the object has the time-dependence trait. + +This fallback method throws an error indicating the object does not support +time-dependence queries. Concrete types that have the trait should implement +`has_time_dependence_trait(obj::MyType) = true`. + +The calling function name is automatically detected from the stacktrace +for better error messages. + +# Arguments +- `obj::Any`: The object to check. + +# Throws +- [`CTBase.Exceptions.IncorrectArgument`](@extref): Always, indicating the object does not have the trait. + +See also: [`CTBase.Traits.TimeDependence`](@ref), [`CTBase.Traits.time_dependence`](@ref). +""" +function has_time_dependence_trait(obj::Any) + source_method = _caller_function_name() + throw(Exceptions.IncorrectArgument( + "Cannot call $(source_method) on object of type $(typeof(obj)): no time-dependence trait"; + suggestion = "Implement has_time_dependence_trait(obj::$(typeof(obj))) = true and time_dependence(obj::$(typeof(obj))) to enable time-dependence trait support.", + context = "Time-dependence trait not available", + )) +end + +""" +$(TYPEDSIGNATURES) + +Return the time-dependence trait value for the object. + +This fallback method throws an error indicating the method is not implemented. +Concrete types that have the trait should implement `time_dependence(obj::MyType)` +to return the specific trait value (`Autonomous` or `NonAutonomous`). + +# Arguments +- `obj::Any`: The object to query. + +# Throws +- [`CTBase.Exceptions.NotImplemented`](@extref): Always, indicating the method must be implemented. + +See also: [`CTBase.Traits.TimeDependence`](@ref), [`CTBase.Traits.has_time_dependence_trait`](@ref). +""" +function time_dependence(obj::Any) + has_time_dependence_trait(obj) + throw(Exceptions.NotImplemented( + "time_dependence not implemented for $(typeof(obj))"; + required_method = "time_dependence(obj::$(typeof(obj)))", + suggestion = "Implement time_dependence for your concrete object type to return the specific time-dependence trait (Autonomous or NonAutonomous).", + context = "Time-dependence trait - required method implementation", + )) +end + +""" +$(TYPEDSIGNATURES) + +Return true if the object is autonomous (time-independent). + +Checks that the object has the time-dependence trait, then returns true +if `time_dependence(obj)` is `Autonomous`. + +# Arguments +- `obj::Any`: The object to check. + +# Returns +- `Bool`: true if the object is autonomous. + +# Throws +- [`CTBase.Exceptions.IncorrectArgument`](@extref): If the object does not support time-dependence queries. +- [`CTBase.Exceptions.NotImplemented`](@extref): If `time_dependence` is not implemented for the object type. + +See also: [`CTBase.Traits.TimeDependence`](@ref), [`CTBase.Traits.time_dependence`](@ref). +""" +function is_autonomous(obj::Any) + has_time_dependence_trait(obj) + return time_dependence(obj) === Autonomous +end + +""" +$(TYPEDSIGNATURES) + +Return true if the object is non-autonomous (time-dependent). + +Checks that the object has the time-dependence trait, then returns true +if `time_dependence(obj)` is `NonAutonomous`. + +# Arguments +- `obj::Any`: The object to check. + +# Returns +- `Bool`: true if the object is non-autonomous. + +# Throws +- [`CTBase.Exceptions.IncorrectArgument`](@extref): If the object does not support time-dependence queries. +- [`CTBase.Exceptions.NotImplemented`](@extref): If `time_dependence` is not implemented for the object type. + +See also: [`CTBase.Traits.TimeDependence`](@ref), [`CTBase.Traits.time_dependence`](@ref). +""" +function is_nonautonomous(obj::Any) + has_time_dependence_trait(obj) + return time_dependence(obj) === NonAutonomous +end diff --git a/src/Traits/variable_costate.jl b/src/Traits/variable_costate.jl new file mode 100644 index 00000000..1a95bf49 --- /dev/null +++ b/src/Traits/variable_costate.jl @@ -0,0 +1,126 @@ +""" +$(TYPEDEF) + +Abstract base type for variable costate capability traits. + +Variable costate capability traits encode whether a system or flow can integrate +augmented variables (e.g., parameters, controls) and compute their associated +costates. This capability is used for trait-based dispatch in augmented integration. + +Common use cases include: +- Hamiltonian systems: computing the costate of an augmented variable (∂H/∂v integration) +- Optimal control: integrating control variables with their adjoint equations +- Parameter estimation: treating parameters as dynamic variables with derivatives + +# Example +\`\`\`julia-repl +julia> using CTBase.Traits + +julia> SupportsVariableCostate() isa Traits.AbstractVariableCostateCapability +true + +julia> NoVariableCostate() isa Traits.AbstractVariableCostateCapability +true +\`\`\` + +# Notes +- `SupportsVariableCostate` indicates the system can compute derivatives with respect to augmented variables +- `NoVariableCostate` indicates the system cannot compute such derivatives +- This trait is used for dispatch to determine whether augmented integration is possible +- The specific operations enabled depend on the system type and context + +See also: [`CTBase.Traits.SupportsVariableCostate`](@ref), [`CTBase.Traits.NoVariableCostate`](@ref). +""" +abstract type AbstractVariableCostateCapability <: AbstractTrait end + +""" +$(TYPEDEF) + +Trait for systems/flows that support augmented variable integration. + +Indicates that the system or flow can compute derivatives with respect to augmented +variables (e.g., parameters, controls) and integrate their associated costates. +This typically requires automatic differentiation support and variable dependence. + +Common use cases include: +- Hamiltonian systems: computing ∂H/∂v via AD from a scalar Hamiltonian +- Optimal control: integrating control variables with their adjoint equations +- General systems: any system where augmented variables need derivative computation + +# Example +\`\`\`julia-repl +julia> using CTBase.Traits + +julia> svc = SupportsVariableCostate() +SupportsVariableCostate() + +julia> svc isa Traits.AbstractVariableCostateCapability +true +\`\`\` + +# Notes +- Used as a return value from `variable_costate_trait` for systems that support augmented variable integration +- Typically requires AD support and variable dependence in the system +- This trait enables augmented integration operations in flow calls +- The specific implementation depends on the system type and AD backend + +See also: [`CTBase.Traits.AbstractVariableCostateCapability`](@ref), [`CTBase.Traits.NoVariableCostate`](@ref), [`CTBase.Traits.variable_costate_trait`](@ref). +""" +struct SupportsVariableCostate <: AbstractVariableCostateCapability end + +""" +$(TYPEDEF) + +Trait for systems/flows that do not support augmented variable integration. + +Indicates that the system or flow cannot compute derivatives with respect to augmented +variables or integrate their associated costates. This is the default for most systems, +including those with pre-computed derivatives or fixed parameters. + +Common use cases include: +- Hamiltonian systems: pre-computed Hamiltonian vector fields without AD +- Fixed systems: systems with parameters that are not treated as dynamic variables +- General systems: any system where augmented variable integration is not applicable + +# Example +\`\`\`julia-repl +julia> using CTBase.Traits + +julia> nvc = NoVariableCostate() +NoVariableCostate() + +julia> nvc isa Traits.AbstractVariableCostateCapability +true +\`\`\` + +# Notes +- Default return value from `variable_costate_trait` for most systems and flows +- Systems without AD support or with fixed variable dependence typically return this +- Attempting augmented integration operations on such systems will throw an error +- The specific constraints depend on the system type + +See also: [`CTBase.Traits.AbstractVariableCostateCapability`](@ref), [`CTBase.Traits.SupportsVariableCostate`](@ref), [`CTBase.Traits.variable_costate_trait`](@ref). +""" +struct NoVariableCostate <: AbstractVariableCostateCapability end + +""" +$(TYPEDSIGNATURES) + +Return the augmented variable integration capability trait of a system or flow. + +# Arguments +- `obj`: Any object (default implementation returns `NoVariableCostate`). + +# Returns +- `Type{<:AbstractVariableCostateCapability}`: The capability trait, either + `SupportsVariableCostate` or `NoVariableCostate`. + +# Notes +- Default implementation returns `NoVariableCostate` for all objects +- Specialized implementations on system and flow types return the appropriate trait based on the system's capabilities +- Used for dispatch to determine if augmented integration operations are possible +- The specific operations enabled depend on the system type + +See also: [`CTBase.Traits.SupportsVariableCostate`](@ref), [`CTBase.Traits.NoVariableCostate`](@ref). +""" +variable_costate_trait(::Any) = NoVariableCostate diff --git a/src/Traits/variable_dependence.jl b/src/Traits/variable_dependence.jl new file mode 100644 index 00000000..ea1a6120 --- /dev/null +++ b/src/Traits/variable_dependence.jl @@ -0,0 +1,196 @@ +""" +$(TYPEDEF) + +Abstract supertype for variable-dependence traits. + +# Trait Pattern + +Objects that have a variable-dependence trait must implement two methods: +- `has_variable_dependence_trait(obj::MyType) = true`: Indicates the type has this trait +- `variable_dependence(obj::MyType)`: Returns the specific trait value (`Fixed` or `NonFixed`) + +Once these are implemented, the object automatically gains: +- `is_variable(obj)`: Returns true if `variable_dependence(obj)` is `NonFixed` +- `is_nonvariable(obj)`: Returns true if `variable_dependence(obj)` is `Fixed` +- `has_variable(obj)`: Alias for `is_variable` (CTModels compatibility) + +If `has_variable_dependence_trait` is not implemented or returns `false`, +calling `is_variable`, `is_nonvariable`, `has_variable`, or `variable_dependence` will throw an error +indicating the object does not support variable-dependence queries. +""" +abstract type VariableDependence <: AbstractTrait end + +""" +$(TYPEDEF) + +Trait indicating the system or function has no variable parameters. + +Indicates that the system operates with fixed parameters only, without additional +variable arguments that can be treated as dynamic variables during integration. + +Common use cases include: +- Functions with fixed parameters only +- Systems with constant parameters that are not integrated +- Configurations where all parameters are known at compile time + +See also: [`CTBase.Traits.NonFixed`](@ref), [`CTBase.Traits.VariableDependence`](@ref). +""" +struct Fixed <: VariableDependence end + +""" +$(TYPEDEF) + +Trait indicating the system or function depends on variable parameters. + +Indicates that the system operates with additional variable parameters that can +be treated as dynamic variables during integration or optimization. These variables +may be integrated alongside state variables or used for sensitivity analysis. + +Common use cases include: +- Functions with an extra variable argument `v` +- Systems with parameters that vary during integration +- Configurations where parameters are treated as control variables +- Sensitivity analysis and parameter estimation + +See also: [`CTBase.Traits.Fixed`](@ref), [`CTBase.Traits.VariableDependence`](@ref). +""" +struct NonFixed <: VariableDependence end + +# ============================================================================= +# Check has trait +# ============================================================================= + +""" +$(TYPEDSIGNATURES) + +Check if the object has the variable-dependence trait. + +This fallback method throws an error indicating the object does not support +variable-dependence queries. Concrete types that have the trait should implement +`has_variable_dependence_trait(obj::MyType) = true`. + +The calling function name is automatically detected from the stacktrace +for better error messages. + +# Arguments +- `obj::Any`: The object to check. + +# Throws +- [`CTBase.Exceptions.IncorrectArgument`](@extref): Always, indicating the object does not have the trait. + +See also: [`CTBase.Traits.VariableDependence`](@ref), [`CTBase.Traits.variable_dependence`](@ref). +""" +function has_variable_dependence_trait(obj::Any) + source_method = _caller_function_name() + throw(Exceptions.IncorrectArgument( + "Cannot call $(source_method) on object of type $(typeof(obj)): no variable-dependence trait"; + suggestion = "Implement has_variable_dependence_trait(obj::$(typeof(obj))) = true and variable_dependence(obj::$(typeof(obj))) to enable variable-dependence trait support.", + context = "Variable-dependence trait not available", + )) +end + +""" +$(TYPEDSIGNATURES) + +Return the variable-dependence trait value for the object. + +This fallback method throws an error indicating the method is not implemented. +Concrete types that have the trait should implement `variable_dependence(obj::MyType)` +to return the specific trait value (`Fixed` or `NonFixed`). + +# Arguments +- `obj::Any`: The object to query. + +# Throws +- [`CTBase.Exceptions.NotImplemented`](@extref): Always, indicating the method must be implemented. + +See also: [`CTBase.Traits.VariableDependence`](@ref), [`CTBase.Traits.has_variable_dependence_trait`](@ref). +""" +function variable_dependence(obj::Any) + has_variable_dependence_trait(obj) + throw(Exceptions.NotImplemented( + "variable_dependence not implemented for $(typeof(obj))"; + required_method = "variable_dependence(obj::$(typeof(obj)))", + suggestion = "Implement variable_dependence for your concrete object type to return the specific variable-dependence trait (Fixed or NonFixed).", + context = "Variable-dependence trait - required method implementation", + )) +end + +# ============================================================================= +# Trait accessors +# ============================================================================= + +""" +$(TYPEDSIGNATURES) + +Return true if the object depends on variable parameters. + +Checks that the object has the variable-dependence trait, then returns true +if `variable_dependence(obj)` is `NonFixed`. + +# Arguments +- `obj::Any`: The object to check. + +# Returns +- `Bool`: true if the object depends on variable parameters. + +# Throws +- [`CTBase.Exceptions.IncorrectArgument`](@extref): If the object does not support variable-dependence queries. +- [`CTBase.Exceptions.NotImplemented`](@extref): If `variable_dependence` is not implemented for the object type. + +See also: [`CTBase.Traits.VariableDependence`](@ref), [`CTBase.Traits.variable_dependence`](@ref). +""" +function is_variable(obj::Any) + has_variable_dependence_trait(obj) + return variable_dependence(obj) === NonFixed +end + +""" +$(TYPEDSIGNATURES) + +Return true if the object does not depend on variable parameters. + +Checks that the object has the variable-dependence trait, then returns true +if `variable_dependence(obj)` is `Fixed`. + +# Arguments +- `obj::Any`: The object to check. + +# Returns +- `Bool`: true if the object does not depend on variable parameters. + +# Throws +- [`CTBase.Exceptions.IncorrectArgument`](@extref): If the object does not support variable-dependence queries. +- [`CTBase.Exceptions.NotImplemented`](@extref): If `variable_dependence` is not implemented for the object type. + +See also: [`CTBase.Traits.VariableDependence`](@ref), [`CTBase.Traits.variable_dependence`](@ref). +""" +function is_nonvariable(obj::Any) + has_variable_dependence_trait(obj) + return variable_dependence(obj) === Fixed +end + +""" +$(TYPEDSIGNATURES) + +Return true if the object depends on variable parameters. + +Checks that the object has the variable-dependence trait, then returns true +if `variable_dependence(obj)` is `NonFixed`. + +# Arguments +- `obj::Any`: The object to check. + +# Returns +- `Bool`: true if the object depends on variable parameters. + +# Throws +- [`CTBase.Exceptions.IncorrectArgument`](@extref): If the object does not support variable-dependence queries. +- [`CTBase.Exceptions.NotImplemented`](@extref): If `variable_dependence` is not implemented for the object type. + +See also: `is_variable`, [`CTBase.Traits.VariableDependence`](@ref). +""" +function has_variable(obj::Any) + has_variable_dependence_trait(obj) + return variable_dependence(obj) === NonFixed +end From d8395da5f986e58ada7ff4e14cd1bef2fc02930c Mon Sep 17 00:00:00 2001 From: Olivier Cots Date: Tue, 23 Jun 2026 15:46:56 +0200 Subject: [PATCH 3/6] test: add CTBase.Traits test suite Moved from CTFlows and rewired to CTBase.Traits (auto-discovered by the test runner under test/suite/traits/). Co-Authored-By: Claude Opus 4.8 --- test/suite/traits/test_abstract_traits.jl | 42 ++++ test/suite/traits/test_ad.jl | 119 ++++++++++ test/suite/traits/test_dynamics.jl | 129 +++++++++++ test/suite/traits/test_mode.jl | 103 +++++++++ test/suite/traits/test_mutability.jl | 179 +++++++++++++++ test/suite/traits/test_time_dependence.jl | 100 +++++++++ test/suite/traits/test_traits_module.jl | 210 ++++++++++++++++++ test/suite/traits/test_variable_costate.jl | 124 +++++++++++ test/suite/traits/test_variable_dependence.jl | 113 ++++++++++ 9 files changed, 1119 insertions(+) create mode 100644 test/suite/traits/test_abstract_traits.jl create mode 100644 test/suite/traits/test_ad.jl create mode 100644 test/suite/traits/test_dynamics.jl create mode 100644 test/suite/traits/test_mode.jl create mode 100644 test/suite/traits/test_mutability.jl create mode 100644 test/suite/traits/test_time_dependence.jl create mode 100644 test/suite/traits/test_traits_module.jl create mode 100644 test/suite/traits/test_variable_costate.jl create mode 100644 test/suite/traits/test_variable_dependence.jl diff --git a/test/suite/traits/test_abstract_traits.jl b/test/suite/traits/test_abstract_traits.jl new file mode 100644 index 00000000..aba1d0d1 --- /dev/null +++ b/test/suite/traits/test_abstract_traits.jl @@ -0,0 +1,42 @@ +module TestAbstractTraits + +import Test +import CTBase.Traits + +const VERBOSE = isdefined(Main, :TestOptions) ? Main.TestOptions.VERBOSE : true +const SHOWTIMING = isdefined(Main, :TestOptions) ? Main.TestOptions.SHOWTIMING : true + +function test_abstract_traits() + Test.@testset "Abstract Traits Tests" verbose=VERBOSE showtiming=SHOWTIMING begin + + # ==================================================================== + # UNIT TESTS - Abstract Types + # ==================================================================== + + Test.@testset "UNIT TESTS - Abstract Types" begin + Test.@testset "AbstractTrait" begin + Test.@testset "AbstractTrait is exported" begin + Test.@test isdefined(Traits, :AbstractTrait) + end + + Test.@testset "AbstractTrait is abstract" begin + Test.@test isabstracttype(Traits.AbstractTrait) + end + end + end + + # ==================================================================== + # Exports Verification + # ==================================================================== + + Test.@testset "Exports Verification" begin + Test.@testset "Exported abstract trait" begin + Test.@test isdefined(Traits, :AbstractTrait) + end + end + end +end + +end # module + +test_abstract_traits() = TestAbstractTraits.test_abstract_traits() diff --git a/test/suite/traits/test_ad.jl b/test/suite/traits/test_ad.jl new file mode 100644 index 00000000..39fdc4a4 --- /dev/null +++ b/test/suite/traits/test_ad.jl @@ -0,0 +1,119 @@ +module TestAD + +import Test +import CTBase.Traits + +const VERBOSE = isdefined(Main, :TestOptions) ? Main.TestOptions.VERBOSE : true +const SHOWTIMING = isdefined(Main, :TestOptions) ? Main.TestOptions.SHOWTIMING : true + +function test_ad() + Test.@testset "AD Trait Tests" verbose=VERBOSE showtiming=SHOWTIMING begin + + # ==================================================================== + # UNIT TESTS - Abstract Types + # ==================================================================== + + Test.@testset "UNIT TESTS - Abstract Types" begin + Test.@testset "AbstractADTrait" begin + Test.@testset "AbstractADTrait is exported" begin + Test.@test isdefined(Traits, :AbstractADTrait) + end + + Test.@testset "AbstractADTrait is abstract" begin + Test.@test isabstracttype(Traits.AbstractADTrait) + end + + Test.@testset "AbstractADTrait subtypes AbstractTrait" begin + Test.@test Traits.AbstractADTrait <: Traits.AbstractTrait + end + end + end + + # ==================================================================== + # UNIT TESTS - Concrete Trait Types + # ==================================================================== + + Test.@testset "UNIT TESTS - Concrete Trait Types" begin + Test.@testset "WithAD" begin + Test.@testset "WithAD is exported" begin + Test.@test isdefined(Traits, :WithAD) + end + + Test.@testset "WithAD is concrete" begin + Test.@test !isabstracttype(Traits.WithAD) + end + + Test.@testset "WithAD instantiates" begin + with = Traits.WithAD() + Test.@test with isa Traits.WithAD + end + + Test.@testset "WithAD subtypes AbstractADTrait" begin + Test.@test Traits.WithAD <: Traits.AbstractADTrait + end + end + + Test.@testset "WithoutAD" begin + Test.@testset "WithoutAD is exported" begin + Test.@test isdefined(Traits, :WithoutAD) + end + + Test.@testset "WithoutAD is concrete" begin + Test.@test !isabstracttype(Traits.WithoutAD) + end + + Test.@testset "WithoutAD instantiates" begin + without = Traits.WithoutAD() + Test.@test without isa Traits.WithoutAD + end + + Test.@testset "WithoutAD subtypes AbstractADTrait" begin + Test.@test Traits.WithoutAD <: Traits.AbstractADTrait + end + end + end + + # ==================================================================== + # UNIT TESTS - Type Hierarchy + # ==================================================================== + + Test.@testset "UNIT TESTS - Type Hierarchy" begin + Test.@testset "All AD traits subtype AbstractTrait" begin + Test.@test Traits.WithAD <: Traits.AbstractTrait + Test.@test Traits.WithoutAD <: Traits.AbstractTrait + end + end + + # ==================================================================== + # UNIT TESTS - ad_trait function + # ==================================================================== + + Test.@testset "UNIT TESTS - ad_trait function" begin + Test.@testset "ad_trait default returns WithoutAD" begin + Test.@test Traits.ad_trait(42) === Traits.WithoutAD + Test.@test Traits.ad_trait("anything") === Traits.WithoutAD + Test.@test Traits.ad_trait(nothing) === Traits.WithoutAD + end + end + + # ==================================================================== + # Exports Verification + # ==================================================================== + + Test.@testset "Exports Verification" begin + Test.@testset "Exported AD trait types" begin + for sym in (:AbstractADTrait, :WithAD, :WithoutAD) + Test.@test isdefined(Traits, sym) + end + end + + Test.@testset "Exported ad_trait function" begin + Test.@test isdefined(Traits, :ad_trait) + end + end + end +end + +end # module + +test_ad() = TestAD.test_ad() diff --git a/test/suite/traits/test_dynamics.jl b/test/suite/traits/test_dynamics.jl new file mode 100644 index 00000000..c2e463d4 --- /dev/null +++ b/test/suite/traits/test_dynamics.jl @@ -0,0 +1,129 @@ +module TestDynamics + +import Test +import CTBase.Traits + +const VERBOSE = isdefined(Main, :TestOptions) ? Main.TestOptions.VERBOSE : true +const SHOWTIMING = isdefined(Main, :TestOptions) ? Main.TestOptions.SHOWTIMING : true + +function test_dynamics() + Test.@testset "Dynamics Trait Tests" verbose=VERBOSE showtiming=SHOWTIMING begin + + # ==================================================================== + # UNIT TESTS - Abstract Types + # ==================================================================== + + Test.@testset "UNIT TESTS - Abstract Types" begin + Test.@testset "AbstractDynamicsTrait" begin + Test.@testset "AbstractDynamicsTrait is exported" begin + Test.@test isdefined(Traits, :AbstractDynamicsTrait) + end + + Test.@testset "AbstractDynamicsTrait is abstract" begin + Test.@test isabstracttype(Traits.AbstractDynamicsTrait) + end + + Test.@testset "AbstractDynamicsTrait subtypes AbstractTrait" begin + Test.@test Traits.AbstractDynamicsTrait <: Traits.AbstractTrait + end + end + end + + # ==================================================================== + # UNIT TESTS - Concrete Trait Types + # ==================================================================== + + Test.@testset "UNIT TESTS - Concrete Trait Types" begin + Test.@testset "StateDynamics" begin + Test.@testset "StateDynamics is exported" begin + Test.@test isdefined(Traits, :StateDynamics) + end + + Test.@testset "StateDynamics is concrete" begin + Test.@test !isabstracttype(Traits.StateDynamics) + end + + Test.@testset "StateDynamics instantiates" begin + st = Traits.StateDynamics() + Test.@test st isa Traits.StateDynamics + end + + Test.@testset "StateDynamics subtypes AbstractDynamicsTrait" begin + Test.@test Traits.StateDynamics <: Traits.AbstractDynamicsTrait + end + end + + Test.@testset "HamiltonianDynamics" begin + Test.@testset "HamiltonianDynamics is exported" begin + Test.@test isdefined(Traits, :HamiltonianDynamics) + end + + Test.@testset "HamiltonianDynamics is concrete" begin + Test.@test !isabstracttype(Traits.HamiltonianDynamics) + end + + Test.@testset "HamiltonianDynamics instantiates" begin + ham = Traits.HamiltonianDynamics() + Test.@test ham isa Traits.HamiltonianDynamics + end + + Test.@testset "HamiltonianDynamics subtypes AbstractDynamicsTrait" begin + Test.@test Traits.HamiltonianDynamics <: Traits.AbstractDynamicsTrait + end + end + + Test.@testset "AugmentedHamiltonianDynamics" begin + Test.@testset "AugmentedHamiltonianDynamics is exported" begin + Test.@test isdefined(Traits, :AugmentedHamiltonianDynamics) + end + + Test.@testset "AugmentedHamiltonianDynamics is concrete" begin + Test.@test !isabstracttype(Traits.AugmentedHamiltonianDynamics) + end + + Test.@testset "AugmentedHamiltonianDynamics instantiates" begin + aug = Traits.AugmentedHamiltonianDynamics() + Test.@test aug isa Traits.AugmentedHamiltonianDynamics + end + + Test.@testset "AugmentedHamiltonianDynamics subtypes AbstractDynamicsTrait" begin + Test.@test Traits.AugmentedHamiltonianDynamics <: Traits.AbstractDynamicsTrait + end + end + end + + # ==================================================================== + # UNIT TESTS - Type Hierarchy + # ==================================================================== + + Test.@testset "UNIT TESTS - Type Hierarchy" begin + Test.@testset "All dynamics traits subtype AbstractTrait" begin + Test.@test Traits.StateDynamics <: Traits.AbstractTrait + Test.@test Traits.HamiltonianDynamics <: Traits.AbstractTrait + Test.@test Traits.AugmentedHamiltonianDynamics <: Traits.AbstractTrait + end + + Test.@testset "Dynamics traits are distinct from mode traits" begin + Test.@test !(Traits.StateDynamics <: Traits.AbstractModeTrait) + Test.@test !(Traits.HamiltonianDynamics <: Traits.AbstractModeTrait) + Test.@test !(Traits.AugmentedHamiltonianDynamics <: Traits.AbstractModeTrait) + end + end + + # ==================================================================== + # Exports Verification + # ==================================================================== + + Test.@testset "Exports Verification" begin + Test.@testset "Exported dynamics trait types" begin + for sym in (:AbstractDynamicsTrait, :StateDynamics, :HamiltonianDynamics, :AugmentedHamiltonianDynamics) + Test.@test isdefined(Traits, sym) + end + end + end + end +end + +end # module + +test_dynamics() = TestDynamics.test_dynamics() diff --git a/test/suite/traits/test_mode.jl b/test/suite/traits/test_mode.jl new file mode 100644 index 00000000..d8d7ce1d --- /dev/null +++ b/test/suite/traits/test_mode.jl @@ -0,0 +1,103 @@ +module TestMode + +import Test +import CTBase.Traits + +const VERBOSE = isdefined(Main, :TestOptions) ? Main.TestOptions.VERBOSE : true +const SHOWTIMING = isdefined(Main, :TestOptions) ? Main.TestOptions.SHOWTIMING : true + +function test_mode() + Test.@testset "Mode Trait Tests" verbose=VERBOSE showtiming=SHOWTIMING begin + + # ==================================================================== + # UNIT TESTS - Abstract Types + # ==================================================================== + + Test.@testset "UNIT TESTS - Abstract Types" begin + Test.@testset "AbstractModeTrait" begin + Test.@testset "AbstractModeTrait is exported" begin + Test.@test isdefined(Traits, :AbstractModeTrait) + end + + Test.@testset "AbstractModeTrait is abstract" begin + Test.@test isabstracttype(Traits.AbstractModeTrait) + end + + Test.@testset "AbstractModeTrait subtypes AbstractTrait" begin + Test.@test Traits.AbstractModeTrait <: Traits.AbstractTrait + end + end + end + + # ==================================================================== + # UNIT TESTS - Concrete Trait Types + # ==================================================================== + + Test.@testset "UNIT TESTS - Concrete Trait Types" begin + Test.@testset "EndPointMode" begin + Test.@testset "EndPointMode is exported" begin + Test.@test isdefined(Traits, :EndPointMode) + end + + Test.@testset "EndPointMode is concrete" begin + Test.@test !isabstracttype(Traits.EndPointMode) + end + + Test.@testset "EndPointMode instantiates" begin + pt = Traits.EndPointMode() + Test.@test pt isa Traits.EndPointMode + end + + Test.@testset "EndPointMode subtypes AbstractModeTrait" begin + Test.@test Traits.EndPointMode <: Traits.AbstractModeTrait + end + end + + Test.@testset "TrajectoryMode" begin + Test.@testset "TrajectoryMode is exported" begin + Test.@test isdefined(Traits, :TrajectoryMode) + end + + Test.@testset "TrajectoryMode is concrete" begin + Test.@test !isabstracttype(Traits.TrajectoryMode) + end + + Test.@testset "TrajectoryMode instantiates" begin + traj = Traits.TrajectoryMode() + Test.@test traj isa Traits.TrajectoryMode + end + + Test.@testset "TrajectoryMode subtypes AbstractModeTrait" begin + Test.@test Traits.TrajectoryMode <: Traits.AbstractModeTrait + end + end + end + + # ==================================================================== + # UNIT TESTS - Type Hierarchy + # ==================================================================== + + Test.@testset "UNIT TESTS - Type Hierarchy" begin + Test.@testset "All mode traits subtype AbstractTrait" begin + Test.@test Traits.EndPointMode <: Traits.AbstractTrait + Test.@test Traits.TrajectoryMode <: Traits.AbstractTrait + end + end + + # ==================================================================== + # Exports Verification + # ==================================================================== + + Test.@testset "Exports Verification" begin + Test.@testset "Exported mode trait types" begin + for sym in (:AbstractModeTrait, :EndPointMode, :TrajectoryMode) + Test.@test isdefined(Traits, sym) + end + end + end + end +end + +end # module + +test_mode() = TestMode.test_mode() diff --git a/test/suite/traits/test_mutability.jl b/test/suite/traits/test_mutability.jl new file mode 100644 index 00000000..3c9350b1 --- /dev/null +++ b/test/suite/traits/test_mutability.jl @@ -0,0 +1,179 @@ +module TestMutability + +import Test +import CTBase.Exceptions +import CTBase.Traits + +const VERBOSE = isdefined(Main, :TestOptions) ? Main.TestOptions.VERBOSE : true +const SHOWTIMING = isdefined(Main, :TestOptions) ? Main.TestOptions.SHOWTIMING : true + +# ============================================================================== +# Fake types for contract testing +# ============================================================================== + +""" +Fake type for testing mutability trait pattern with InPlace. +""" +struct FakeInPlace end + +Traits.has_mutability_trait(::FakeInPlace) = true +Traits.mutability(::FakeInPlace) = Traits.InPlace + +""" +Fake type for testing mutability trait pattern with OutOfPlace. +""" +struct FakeOutOfPlace end + +Traits.has_mutability_trait(::FakeOutOfPlace) = true +Traits.mutability(::FakeOutOfPlace) = Traits.OutOfPlace + +""" +Fake type for testing mutability trait without the trait. +""" +struct FakeNoMutability end + +function test_mutability() + Test.@testset "Mutability Trait Tests" verbose=VERBOSE showtiming=SHOWTIMING begin + + # ==================================================================== + # UNIT TESTS - Abstract Types + # ==================================================================== + + Test.@testset "UNIT TESTS - Abstract Types" begin + Test.@testset "AbstractMutabilityTrait" begin + Test.@testset "AbstractMutabilityTrait is exported" begin + Test.@test isdefined(Traits, :AbstractMutabilityTrait) + end + + Test.@testset "AbstractMutabilityTrait is abstract" begin + Test.@test isabstracttype(Traits.AbstractMutabilityTrait) + end + + Test.@testset "AbstractMutabilityTrait subtypes AbstractTrait" begin + Test.@test Traits.AbstractMutabilityTrait <: Traits.AbstractTrait + end + end + end + + # ==================================================================== + # UNIT TESTS - Concrete Trait Types + # ==================================================================== + + Test.@testset "UNIT TESTS - Concrete Trait Types" begin + Test.@testset "InPlace" begin + Test.@testset "InPlace is exported" begin + Test.@test isdefined(Traits, :InPlace) + end + + Test.@testset "InPlace is concrete" begin + Test.@test !isabstracttype(Traits.InPlace) + end + + Test.@testset "InPlace instantiates" begin + ip = Traits.InPlace() + Test.@test ip isa Traits.InPlace + end + + Test.@testset "InPlace subtypes AbstractMutabilityTrait" begin + Test.@test Traits.InPlace <: Traits.AbstractMutabilityTrait + end + end + + Test.@testset "OutOfPlace" begin + Test.@testset "OutOfPlace is exported" begin + Test.@test isdefined(Traits, :OutOfPlace) + end + + Test.@testset "OutOfPlace is concrete" begin + Test.@test !isabstracttype(Traits.OutOfPlace) + end + + Test.@testset "OutOfPlace instantiates" begin + oop = Traits.OutOfPlace() + Test.@test oop isa Traits.OutOfPlace + end + + Test.@testset "OutOfPlace subtypes AbstractMutabilityTrait" begin + Test.@test Traits.OutOfPlace <: Traits.AbstractMutabilityTrait + end + end + end + + # ==================================================================== + # UNIT TESTS - Type Hierarchy + # ==================================================================== + + Test.@testset "UNIT TESTS - Type Hierarchy" begin + Test.@testset "All mutability traits subtype AbstractTrait" begin + Test.@test Traits.InPlace <: Traits.AbstractTrait + Test.@test Traits.OutOfPlace <: Traits.AbstractTrait + end + end + + # ==================================================================== + # ERROR TESTS - Fallback Methods + # ==================================================================== + + Test.@testset "ERROR TESTS - Fallback Methods" begin + Test.@testset "has_mutability_trait throws IncorrectArgument" begin + obj = "not a trait object" + Test.@test_throws Exceptions.IncorrectArgument Traits.has_mutability_trait(obj) + end + + Test.@testset "mutability throws IncorrectArgument" begin + obj = "not a trait object" + Test.@test_throws Exceptions.IncorrectArgument Traits.mutability(obj) + end + end + + # ==================================================================== + # CONTRACT TESTS - Mutability Trait Pattern + # ==================================================================== + + Test.@testset "CONTRACT TESTS - Mutability Trait Pattern" begin + Test.@testset "FakeInPlace trait implementation" begin + obj = FakeInPlace() + Test.@test Traits.has_mutability_trait(obj) === true + Test.@test Traits.mutability(obj) === Traits.InPlace + Test.@test Traits.is_inplace(obj) === true + Test.@test Traits.is_outofplace(obj) === false + end + + Test.@testset "FakeOutOfPlace trait implementation" begin + obj = FakeOutOfPlace() + Test.@test Traits.has_mutability_trait(obj) === true + Test.@test Traits.mutability(obj) === Traits.OutOfPlace + Test.@test Traits.is_inplace(obj) === false + Test.@test Traits.is_outofplace(obj) === true + end + + Test.@testset "FakeNoMutability throws errors" begin + obj = FakeNoMutability() + Test.@test_throws Exceptions.IncorrectArgument Traits.is_inplace(obj) + Test.@test_throws Exceptions.IncorrectArgument Traits.mutability(obj) + end + end + + # ==================================================================== + # Exports Verification + # ==================================================================== + + Test.@testset "Exports Verification" begin + Test.@testset "Exported mutability trait types" begin + for sym in (:AbstractMutabilityTrait, :InPlace, :OutOfPlace) + Test.@test isdefined(Traits, sym) + end + end + + Test.@testset "Exported mutability trait functions" begin + for sym in (:has_mutability_trait, :mutability, :is_inplace, :is_outofplace) + Test.@test isdefined(Traits, sym) + end + end + end + end +end + +end # module + +test_mutability() = TestMutability.test_mutability() diff --git a/test/suite/traits/test_time_dependence.jl b/test/suite/traits/test_time_dependence.jl new file mode 100644 index 00000000..801b09a5 --- /dev/null +++ b/test/suite/traits/test_time_dependence.jl @@ -0,0 +1,100 @@ +module TestTimeDependence + +import Test +import CTBase.Exceptions +import CTBase.Traits + +const VERBOSE = isdefined(Main, :TestOptions) ? Main.TestOptions.VERBOSE : true +const SHOWTIMING = isdefined(Main, :TestOptions) ? Main.TestOptions.SHOWTIMING : true + +# ============================================================================== +# Fake types for contract testing +# ============================================================================== + +""" +Fake type for testing time-dependence trait pattern. +Implements both required methods: has_time_dependence_trait and time_dependence. +""" +struct FakeAutonomous end + +Traits.has_time_dependence_trait(::FakeAutonomous; kwargs...) = true +Traits.time_dependence(::FakeAutonomous) = Traits.Autonomous + +""" +Fake type for testing time-dependence trait pattern with NonAutonomous. +""" +struct FakeNonAutonomous end + +Traits.has_time_dependence_trait(::FakeNonAutonomous) = true +Traits.time_dependence(::FakeNonAutonomous) = Traits.NonAutonomous + +function test_time_dependence() + Test.@testset "Time Dependence Trait Tests" verbose=VERBOSE showtiming=SHOWTIMING begin + + # ==================================================================== + # UNIT TESTS - Trait Types + # ==================================================================== + + Test.@testset "UNIT TESTS - Trait Types" begin + Test.@testset "TimeDependence abstract type" begin + Test.@test isdefined(Traits, :TimeDependence) + Test.@test Traits.Autonomous <: Traits.TimeDependence + Test.@test Traits.NonAutonomous <: Traits.TimeDependence + end + end + + # ==================================================================== + # ERROR TESTS - Fallback Methods + # ==================================================================== + + Test.@testset "ERROR TESTS - Fallback Methods" begin + Test.@testset "has_time_dependence_trait throws IncorrectArgument" begin + obj = "not a trait object" + Test.@test_throws Exceptions.IncorrectArgument Traits.has_time_dependence_trait(obj) + end + + Test.@testset "time_dependence throws IncorrectArgument" begin + obj = "not a trait object" + Test.@test_throws Exceptions.IncorrectArgument Traits.time_dependence(obj) + end + end + + # ==================================================================== + # CONTRACT TESTS - Time-Dependence Trait Pattern + # ==================================================================== + + Test.@testset "CONTRACT TESTS - Time-Dependence Trait Pattern" begin + Test.@testset "FakeAutonomous trait implementation" begin + obj = FakeAutonomous() + Test.@test Traits.has_time_dependence_trait(obj) === true + Test.@test Traits.time_dependence(obj) === Traits.Autonomous + Test.@test Traits.is_autonomous(obj) === true + Test.@test Traits.is_nonautonomous(obj) === false + end + + Test.@testset "FakeNonAutonomous trait implementation" begin + obj = FakeNonAutonomous() + Test.@test Traits.has_time_dependence_trait(obj) === true + Test.@test Traits.time_dependence(obj) === Traits.NonAutonomous + Test.@test Traits.is_autonomous(obj) === false + Test.@test Traits.is_nonautonomous(obj) === true + end + end + + # ==================================================================== + # Exports Verification + # ==================================================================== + + Test.@testset "Exports Verification" begin + Test.@testset "Exported time-dependence trait functions" begin + for sym in (:has_time_dependence_trait, :time_dependence) + Test.@test isdefined(Traits, sym) + end + end + end + end +end + +end # module + +test_time_dependence() = TestTimeDependence.test_time_dependence() diff --git a/test/suite/traits/test_traits_module.jl b/test/suite/traits/test_traits_module.jl new file mode 100644 index 00000000..13098529 --- /dev/null +++ b/test/suite/traits/test_traits_module.jl @@ -0,0 +1,210 @@ +""" +# ============================================================================ +# Traits Module Exports Tests +# ============================================================================ +# This file tests the exports from the `Traits` module. It verifies that +# the expected types and functions are properly exported by +# `CTBase.Traits` and readily accessible to the end user. +# +# Functionality tests are in separate files: +# - test_abstract_traits.jl for abstract trait types +# - test_ad.jl for AD traits +# - test_dynamics.jl for dynamics traits +# - test_mode.jl for mode traits +# - test_mutability.jl for mutability traits +# - test_time_dependence.jl for time dependence traits +# - test_variable_costate.jl for variable costate traits +# - test_variable_dependence.jl for variable dependence traits +""" + +module TestTraitsModule + +import Test +import CTBase +import CTBase.Traits +using CTBase.Traits # For testing exported symbols + +const VERBOSE = isdefined(Main, :TestOptions) ? Main.TestOptions.VERBOSE : true +const SHOWTIMING = isdefined(Main, :TestOptions) ? Main.TestOptions.SHOWTIMING : true + +const CurrentModule = TestTraitsModule + +# ============================================================================ +# Hardcoded export lists +# ============================================================================ +# These lists define the expected public API of the Traits module. + +const EXPORTED_ABSTRACT_TYPES = ( + :AbstractTrait, + :AbstractModeTrait, + :AbstractDynamicsTrait, + :AbstractMutabilityTrait, + :AbstractADTrait, + :AbstractVariableCostateCapability, + :TimeDependence, + :VariableDependence, +) + +const EXPORTED_CONCRETE_TYPES = ( + :EndPointMode, + :TrajectoryMode, + :StateDynamics, + :HamiltonianDynamics, + :AugmentedHamiltonianDynamics, + :InPlace, + :OutOfPlace, + :WithAD, + :WithoutAD, + :SupportsVariableCostate, + :NoVariableCostate, + :Autonomous, + :NonAutonomous, + :Fixed, + :NonFixed, +) + +const EXPORTED_FUNCTIONS = ( + :ad_trait, + :variable_costate_trait, + :is_inplace, + :is_outofplace, + :has_time_dependence_trait, + :time_dependence, + :has_mutability_trait, + :mutability, + :has_variable_dependence_trait, + :variable_dependence, + :is_autonomous, + :is_nonautonomous, + :is_variable, + :is_nonvariable, + :has_variable, +) + +const PRIVATE_SYMBOLS = ( + :_caller_function_name, +) + +# ============================================================================ +# Helper functions (generic for reuse in other modules) +# ============================================================================ + +""" + test_exported_symbols(module_ref::Module, symbols::Tuple, test_module::Module) + +Test that symbols are exported from a module and available via `using`. +""" +function test_exported_symbols(module_ref::Module, symbols::Tuple, test_module::Module) + for sym in symbols + Test.@testset "$(sym)" begin + Test.@test isdefined(module_ref, sym) + Test.@test isdefined(test_module, sym) + end + end +end + +""" + test_internal_symbols(module_ref::Module, symbols::Tuple, test_module::Module) + +Test that symbols are defined in a module but NOT exported (not available via `using`). +Generic helper for modules with private symbols. +""" +function test_internal_symbols(module_ref::Module, symbols::Tuple, test_module::Module) + for sym in symbols + Test.@testset "$(sym)" begin + Test.@test isdefined(module_ref, sym) + Test.@test !isdefined(test_module, sym) + end + end +end + +# ============================================================================ +# Test function +# ============================================================================ + +function test_traits_module() + Test.@testset "Traits Module Exports" verbose=VERBOSE showtiming=SHOWTIMING begin + + # ==================================================================== + # Module availability + # ==================================================================== + + Test.@testset "Module availability" begin + Test.@testset "Traits module exists" begin + Test.@test isdefined(CTBase, :Traits) + Test.@test CTBase.Traits isa Module + end + end + + # ==================================================================== + # Exported abstract types verification + # ==================================================================== + + Test.@testset "Exported abstract types" begin + test_exported_symbols(Traits, EXPORTED_ABSTRACT_TYPES, CurrentModule) + end + + # ==================================================================== + # Exported concrete types verification + # ==================================================================== + + Test.@testset "Exported concrete types" begin + test_exported_symbols(Traits, EXPORTED_CONCRETE_TYPES, CurrentModule) + end + + # ==================================================================== + # Exported functions verification + # ==================================================================== + + Test.@testset "Exported functions" begin + test_exported_symbols(Traits, EXPORTED_FUNCTIONS, CurrentModule) + end + + # ==================================================================== + # Private symbols (not exported) verification + # ==================================================================== + + Test.@testset "Private symbols (not exported)" begin + test_internal_symbols(Traits, PRIVATE_SYMBOLS, CurrentModule) + end + + # ==================================================================== + # Type hierarchy tests + # ==================================================================== + + Test.@testset "Type hierarchy" begin + Test.@testset "Abstract types are abstract" begin + Test.@test isabstracttype(Traits.AbstractTrait) + Test.@test isabstracttype(Traits.AbstractModeTrait) + Test.@test isabstracttype(Traits.AbstractDynamicsTrait) + Test.@test isabstracttype(Traits.AbstractMutabilityTrait) + Test.@test isabstracttype(Traits.AbstractADTrait) + Test.@test isabstracttype(Traits.AbstractVariableCostateCapability) + Test.@test isabstracttype(Traits.TimeDependence) + Test.@test isabstracttype(Traits.VariableDependence) + end + + Test.@testset "Concrete types inherit from abstract types" begin + Test.@test Traits.EndPointMode <: Traits.AbstractModeTrait + Test.@test Traits.TrajectoryMode <: Traits.AbstractModeTrait + Test.@test Traits.StateDynamics <: Traits.AbstractDynamicsTrait + Test.@test Traits.HamiltonianDynamics <: Traits.AbstractDynamicsTrait + Test.@test Traits.AugmentedHamiltonianDynamics <: Traits.AbstractDynamicsTrait + Test.@test Traits.InPlace <: Traits.AbstractMutabilityTrait + Test.@test Traits.OutOfPlace <: Traits.AbstractMutabilityTrait + Test.@test Traits.WithAD <: Traits.AbstractADTrait + Test.@test Traits.WithoutAD <: Traits.AbstractADTrait + Test.@test Traits.SupportsVariableCostate <: Traits.AbstractVariableCostateCapability + Test.@test Traits.NoVariableCostate <: Traits.AbstractVariableCostateCapability + Test.@test Traits.Autonomous <: Traits.TimeDependence + Test.@test Traits.NonAutonomous <: Traits.TimeDependence + Test.@test Traits.Fixed <: Traits.VariableDependence + Test.@test Traits.NonFixed <: Traits.VariableDependence + end + end + end +end + +end # module + +test_traits_module() = TestTraitsModule.test_traits_module() diff --git a/test/suite/traits/test_variable_costate.jl b/test/suite/traits/test_variable_costate.jl new file mode 100644 index 00000000..c85a0a0e --- /dev/null +++ b/test/suite/traits/test_variable_costate.jl @@ -0,0 +1,124 @@ +module TestVariableCostate + +import Test +import CTBase.Traits + +const VERBOSE = isdefined(Main, :TestOptions) ? Main.TestOptions.VERBOSE : true +const SHOWTIMING = isdefined(Main, :TestOptions) ? Main.TestOptions.SHOWTIMING : true + +function test_variable_costate() + Test.@testset "Variable Costate Trait Tests" verbose=VERBOSE showtiming=SHOWTIMING begin + + # ==================================================================== + # UNIT TESTS - Abstract Types + # ==================================================================== + + Test.@testset "UNIT TESTS - Abstract Types" begin + Test.@testset "AbstractVariableCostateCapability" begin + Test.@testset "AbstractVariableCostateCapability is exported" begin + Test.@test isdefined(Traits, :AbstractVariableCostateCapability) + end + + Test.@testset "AbstractVariableCostateCapability is abstract" begin + Test.@test isabstracttype(Traits.AbstractVariableCostateCapability) + end + + Test.@testset "AbstractVariableCostateCapability subtypes AbstractTrait" begin + Test.@test Traits.AbstractVariableCostateCapability <: Traits.AbstractTrait + end + end + end + + # ==================================================================== + # UNIT TESTS - Concrete Trait Types + # ==================================================================== + + Test.@testset "UNIT TESTS - Concrete Trait Types" begin + Test.@testset "SupportsVariableCostate" begin + Test.@testset "SupportsVariableCostate is exported" begin + Test.@test isdefined(Traits, :SupportsVariableCostate) + end + + Test.@testset "SupportsVariableCostate is concrete" begin + Test.@test !isabstracttype(Traits.SupportsVariableCostate) + end + + Test.@testset "SupportsVariableCostate instantiates" begin + svc = Traits.SupportsVariableCostate() + Test.@test svc isa Traits.SupportsVariableCostate + end + + Test.@testset "SupportsVariableCostate subtypes AbstractVariableCostateCapability" begin + Test.@test Traits.SupportsVariableCostate <: Traits.AbstractVariableCostateCapability + end + end + + Test.@testset "NoVariableCostate" begin + Test.@testset "NoVariableCostate is exported" begin + Test.@test isdefined(Traits, :NoVariableCostate) + end + + Test.@testset "NoVariableCostate is concrete" begin + Test.@test !isabstracttype(Traits.NoVariableCostate) + end + + Test.@testset "NoVariableCostate instantiates" begin + nvc = Traits.NoVariableCostate() + Test.@test nvc isa Traits.NoVariableCostate + end + + Test.@testset "NoVariableCostate subtypes AbstractVariableCostateCapability" begin + Test.@test Traits.NoVariableCostate <: Traits.AbstractVariableCostateCapability + end + end + end + + # ==================================================================== + # UNIT TESTS - Type Hierarchy + # ==================================================================== + + Test.@testset "UNIT TESTS - Type Hierarchy" begin + Test.@testset "All variable costate traits subtype AbstractTrait" begin + Test.@test Traits.SupportsVariableCostate <: Traits.AbstractTrait + Test.@test Traits.NoVariableCostate <: Traits.AbstractTrait + end + + Test.@testset "Variable costate traits subtype AbstractVariableCostateCapability" begin + Test.@test Traits.SupportsVariableCostate <: Traits.AbstractVariableCostateCapability + Test.@test Traits.NoVariableCostate <: Traits.AbstractVariableCostateCapability + end + end + + # ==================================================================== + # UNIT TESTS - variable_costate_trait function + # ==================================================================== + + Test.@testset "UNIT TESTS - variable_costate_trait function" begin + Test.@testset "variable_costate_trait default returns NoVariableCostate" begin + Test.@test Traits.variable_costate_trait(42) === Traits.NoVariableCostate + Test.@test Traits.variable_costate_trait("anything") === Traits.NoVariableCostate + Test.@test Traits.variable_costate_trait(nothing) === Traits.NoVariableCostate + end + end + + # ==================================================================== + # Exports Verification + # ==================================================================== + + Test.@testset "Exports Verification" begin + Test.@testset "Exported variable costate trait types" begin + for sym in (:AbstractVariableCostateCapability, :SupportsVariableCostate, :NoVariableCostate) + Test.@test isdefined(Traits, sym) + end + end + + Test.@testset "Exported variable_costate_trait function" begin + Test.@test isdefined(Traits, :variable_costate_trait) + end + end + end +end + +end # module + +test_variable_costate() = TestVariableCostate.test_variable_costate() diff --git a/test/suite/traits/test_variable_dependence.jl b/test/suite/traits/test_variable_dependence.jl new file mode 100644 index 00000000..c9aff8d8 --- /dev/null +++ b/test/suite/traits/test_variable_dependence.jl @@ -0,0 +1,113 @@ +module TestVariableDependence + +import Test +import CTBase.Exceptions +import CTBase.Traits + +const VERBOSE = isdefined(Main, :TestOptions) ? Main.TestOptions.VERBOSE : true +const SHOWTIMING = isdefined(Main, :TestOptions) ? Main.TestOptions.SHOWTIMING : true + +# ============================================================================== +# Fake types for contract testing +# ============================================================================== + +""" +Fake type for testing variable-dependence trait pattern. +Implements both required methods: has_variable_dependence_trait and variable_dependence. +""" +struct FakeFixed end + +Traits.has_variable_dependence_trait(::FakeFixed) = true +Traits.variable_dependence(::FakeFixed) = Traits.Fixed + +""" +Fake type for testing variable-dependence trait pattern with NonFixed. +""" +struct FakeNonFixed end + +Traits.has_variable_dependence_trait(::FakeNonFixed) = true +Traits.variable_dependence(::FakeNonFixed) = Traits.NonFixed + +function test_variable_dependence() + Test.@testset "Variable Dependence Trait Tests" verbose=VERBOSE showtiming=SHOWTIMING begin + + # ==================================================================== + # UNIT TESTS - Trait Types + # ==================================================================== + + Test.@testset "UNIT TESTS - Trait Types" begin + Test.@testset "VariableDependence abstract type" begin + Test.@test isdefined(Traits, :VariableDependence) + Test.@test Traits.Fixed <: Traits.VariableDependence + Test.@test Traits.NonFixed <: Traits.VariableDependence + end + + Test.@testset "Concrete trait types" begin + Test.@test Traits.Fixed() isa Traits.Fixed + Test.@test Traits.NonFixed() isa Traits.NonFixed + end + end + + # ==================================================================== + # ERROR TESTS - Fallback Methods + # ==================================================================== + + Test.@testset "ERROR TESTS - Fallback Methods" begin + Test.@testset "has_variable_dependence_trait throws IncorrectArgument" begin + obj = "not a trait object" + Test.@test_throws Exceptions.IncorrectArgument Traits.has_variable_dependence_trait(obj) + end + + Test.@testset "variable_dependence throws IncorrectArgument" begin + obj = "not a trait object" + Test.@test_throws Exceptions.IncorrectArgument Traits.variable_dependence(obj) + end + end + + # ==================================================================== + # CONTRACT TESTS - Variable-Dependence Trait Pattern + # ==================================================================== + + Test.@testset "CONTRACT TESTS - Variable-Dependence Trait Pattern" begin + Test.@testset "FakeFixed trait implementation" begin + obj = FakeFixed() + Test.@test Traits.has_variable_dependence_trait(obj) === true + Test.@test Traits.variable_dependence(obj) === Traits.Fixed + Test.@test Traits.is_variable(obj) === false + Test.@test Traits.is_nonvariable(obj) === true + Test.@test Traits.has_variable(obj) === false + end + + Test.@testset "FakeNonFixed trait implementation" begin + obj = FakeNonFixed() + Test.@test Traits.has_variable_dependence_trait(obj) === true + Test.@test Traits.variable_dependence(obj) === Traits.NonFixed + Test.@test Traits.is_variable(obj) === true + Test.@test Traits.is_nonvariable(obj) === false + Test.@test Traits.has_variable(obj) === true + end + end + + # ==================================================================== + # Exports Verification + # ==================================================================== + + Test.@testset "Exports Verification" begin + Test.@testset "Exported variable-dependence trait types" begin + for sym in (:VariableDependence, :Fixed, :NonFixed) + Test.@test isdefined(Traits, sym) + end + end + + Test.@testset "Exported variable-dependence trait functions" begin + for sym in (:has_variable_dependence_trait, :variable_dependence) + Test.@test isdefined(Traits, sym) + end + end + end + end +end + +end # module + +test_variable_dependence() = TestVariableDependence.test_variable_dependence() From 918cb9b79dc1277067edc9dd65aa6fbe4b265cd1 Mon Sep 17 00:00:00 2001 From: Olivier Cots Date: Tue, 23 Jun 2026 15:46:56 +0200 Subject: [PATCH 4/6] docs: add Traits guide and API reference Adds a "Traits" guide under Core Concepts and a Traits API reference page. Co-Authored-By: Claude Opus 4.8 --- docs/api_reference.jl | 7 +++ docs/make.jl | 1 + docs/src/guide/traits.md | 122 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 130 insertions(+) create mode 100644 docs/src/guide/traits.md diff --git a/docs/api_reference.jl b/docs/api_reference.jl index b9c9b3ea..8a4db600 100644 --- a/docs/api_reference.jl +++ b/docs/api_reference.jl @@ -42,6 +42,13 @@ function generate_api_reference(src_dir::String) joinpath("Interpolation", "Interpolation.jl"), joinpath("Interpolation", "types.jl"), joinpath("Interpolation", "ctinterpolate.jl"), joinpath("Interpolation", "display.jl"), )), + (mod=CTBase.Traits, title="Traits", filename="traits", files=src( + joinpath("Traits", "Traits.jl"), joinpath("Traits", "helpers.jl"), + joinpath("Traits", "abstract.jl"), joinpath("Traits", "mode.jl"), + joinpath("Traits", "dynamics.jl"), joinpath("Traits", "ad.jl"), + joinpath("Traits", "variable_costate.jl"), joinpath("Traits", "mutability.jl"), + joinpath("Traits", "time_dependence.jl"), joinpath("Traits", "variable_dependence.jl"), + )), (mod=CTBase.Options, title="Options", filename="options", files=src( joinpath("Options", "Options.jl"), joinpath("Options", "not_provided.jl"), joinpath("Options", "option_value.jl"), joinpath("Options", "option_definition.jl"), diff --git a/docs/make.jl b/docs/make.jl index 6e09b45f..9ef1b8d6 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -72,6 +72,7 @@ with_api_reference(src_dir) do api_pages "Core Concepts" => [ "Descriptions" => joinpath("guide", "descriptions.md"), "Exceptions" => joinpath("guide", "exceptions.md"), + "Traits" => joinpath("guide", "traits.md"), ], "Strategies & Options" => [ "Options System" => joinpath("guide", "options-system.md"), diff --git a/docs/src/guide/traits.md b/docs/src/guide/traits.md new file mode 100644 index 00000000..8a9710c4 --- /dev/null +++ b/docs/src/guide/traits.md @@ -0,0 +1,122 @@ +# Traits: compile-time properties + +```@meta +CurrentModule = CTBase +``` + +[`CTBase.Traits`](@ref CTBase.Traits) provides a small set of **compile-time +traits** shared across the control-toolbox ecosystem. Traits are empty marker +types used as type parameters (or returned by accessor functions) so that +behaviour can be selected by dispatch, with **no runtime cost**. + +```@repl traits +using CTBase +import CTBase.Traits +``` + +Downstream packages use these traits to encode, for example, the **call +signature** of a vector field or Hamiltonian, and to dispatch system builders +without runtime branches. + +## Trait families + +### Time dependence + +Does the object depend on time ``t``? + +| Type | Meaning | +|---|---| +| [`Traits.Autonomous`](@ref CTBase.Traits.Autonomous) | ``t`` is not an argument | +| [`Traits.NonAutonomous`](@ref CTBase.Traits.NonAutonomous) | ``t`` must be supplied | + +Both are abstract subtypes of [`Traits.TimeDependence`](@ref CTBase.Traits.TimeDependence). +They are used as the time-dependence type parameter of `CTModels.Model` and of +CTFlows data wrappers. + +```@repl traits +Traits.Autonomous <: Traits.TimeDependence +Traits.NonAutonomous <: Traits.TimeDependence +``` + +### Variable dependence + +Does the object depend on an extra parameter ``v`` (e.g. a free final time or a +design variable)? + +| Type | Meaning | +|---|---| +| [`Traits.Fixed`](@ref CTBase.Traits.Fixed) | no ``v`` argument | +| [`Traits.NonFixed`](@ref CTBase.Traits.NonFixed) | ``v`` must be supplied | + +```@repl traits +Traits.Fixed <: Traits.VariableDependence +Traits.NonFixed <: Traits.VariableDependence +``` + +### Mutability + +Does a function allocate a new output, or write into a pre-allocated buffer? + +| Type | Meaning | +|---|---| +| [`Traits.OutOfPlace`](@ref CTBase.Traits.OutOfPlace) | returns a new value | +| [`Traits.InPlace`](@ref CTBase.Traits.InPlace) | writes into a buffer (first arg) | + +### Other families + +| Family | Values | +|---|---| +| Integration mode | [`Traits.EndPointMode`](@ref CTBase.Traits.EndPointMode), [`Traits.TrajectoryMode`](@ref CTBase.Traits.TrajectoryMode) | +| Dynamics | [`Traits.StateDynamics`](@ref CTBase.Traits.StateDynamics), [`Traits.HamiltonianDynamics`](@ref CTBase.Traits.HamiltonianDynamics), [`Traits.AugmentedHamiltonianDynamics`](@ref CTBase.Traits.AugmentedHamiltonianDynamics) | +| Automatic differentiation | [`Traits.WithAD`](@ref CTBase.Traits.WithAD), [`Traits.WithoutAD`](@ref CTBase.Traits.WithoutAD) | +| Variable costate | [`Traits.SupportsVariableCostate`](@ref CTBase.Traits.SupportsVariableCostate), [`Traits.NoVariableCostate`](@ref CTBase.Traits.NoVariableCostate) | + +## The trait contract + +A type opts in to a trait by implementing **two methods**: one declaring that it +*has* the trait, and one returning the trait *value*. The boolean predicates +([`Traits.is_autonomous`](@ref CTBase.Traits.is_autonomous), +[`Traits.is_variable`](@ref CTBase.Traits.is_variable), …) then follow +generically — they are not implemented per type. + +For time dependence, implement `has_time_dependence_trait` and `time_dependence`: + +```@repl traits +struct MyObject end + +Traits.has_time_dependence_trait(::MyObject) = true +Traits.time_dependence(::MyObject) = Traits.NonAutonomous + +Traits.has_variable_dependence_trait(::MyObject) = true +Traits.variable_dependence(::MyObject) = Traits.Fixed + +obj = MyObject() +Traits.is_autonomous(obj) # false (derived from time_dependence) +Traits.is_nonautonomous(obj) # true +Traits.is_variable(obj) # false (derived from variable_dependence) +Traits.is_nonvariable(obj) # true +``` + +If a type does not declare a trait, the predicates throw an informative error +rather than returning a wrong default: + +```@repl traits +Traits.is_autonomous(3.14) +``` + +!!! note "Single source of truth" + `Traits.Autonomous` / `Traits.NonAutonomous` are the very types used as the + `CTModels.Model` time-dependence parameter, so `Traits.time_dependence(model)` + and `Traits.is_autonomous(model)` work out of the box on a real optimal + control problem. + +## Accessor / predicate summary + +| Trait value function | Boolean predicates | +|---|---| +| [`Traits.time_dependence`](@ref CTBase.Traits.time_dependence) | `is_autonomous`, `is_nonautonomous` | +| [`Traits.variable_dependence`](@ref CTBase.Traits.variable_dependence) | `is_variable`, `is_nonvariable`, `has_variable` | +| [`Traits.mutability`](@ref CTBase.Traits.mutability) | `is_inplace`, `is_outofplace` | +| [`Traits.ad_trait`](@ref CTBase.Traits.ad_trait) | — | +| [`Traits.variable_costate_trait`](@ref CTBase.Traits.variable_costate_trait) | — | +| [`Traits.dynamics_trait`](@ref CTBase.Traits.dynamics_trait) | — | From 6021fea4b4ad6d68da5e4346764fd365e3e53873 Mon Sep 17 00:00:00 2001 From: Olivier Cots Date: Tue, 23 Jun 2026 16:14:59 +0200 Subject: [PATCH 5/6] Fix docstring compliance in Strategies and Traits modules - Add full module paths to all internal @ref references - Change @extref to @ref for internal symbols (StrategyOptions, Exceptions) - Fixes in abstract_strategy.jl, parameters.jl, describe_registry.jl - Fixes in time_dependence.jl, variable_dependence.jl - Ensures compliance with docstring philosophy from Handbook --- src/Strategies/api/describe_registry.jl | 8 ++++---- src/Strategies/contract/abstract_strategy.jl | 8 ++++---- src/Strategies/contract/parameters.jl | 6 +++--- src/Traits/time_dependence.jl | 18 +++++++++--------- src/Traits/variable_dependence.jl | 16 ++++++++-------- 5 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/Strategies/api/describe_registry.jl b/src/Strategies/api/describe_registry.jl index 7eba821e..a50309b7 100644 --- a/src/Strategies/api/describe_registry.jl +++ b/src/Strategies/api/describe_registry.jl @@ -395,7 +395,7 @@ julia> _strategy_type_name(Collocation) - This is the most common case, handling concrete instantiated types - For parameterized types, each parameter is formatted recursively -See also: [`describe`](@ref), [`_describe_parameter_registry`](@ref) +See also: [`CTBase.Strategies.describe`](@ref), [`CTBase.Strategies._describe_parameter_registry`](@ref) """ function _strategy_type_name(T::DataType) base_name = string(T.name.name) @@ -427,7 +427,7 @@ the type parameter variable name. - This is a fallback for generic types that are not yet instantiated - Less common than the DataType method in typical usage -See also: [`_strategy_type_name(::DataType)`](@ref) +See also: [`CTBase.Strategies._strategy_type_name(::DataType)`](@ref) """ function _strategy_type_name(T::UnionAll) base_name = string(T.body.name.name) @@ -452,7 +452,7 @@ This is the most general fallback method for types that don't match more specifi - This is the ultimate fallback for edge cases - Simply converts the type to a string representation -See also: [`_strategy_type_name(::DataType)`](@ref), [`_strategy_type_name(::UnionAll)`](@ref) +See also: [`CTBase.Strategies._strategy_type_name(::DataType)`](@ref), [`CTBase.Strategies._strategy_type_name(::UnionAll)`](@ref) """ function _strategy_type_name(T::Type) return string(T) @@ -488,7 +488,7 @@ julia> _strategy_base_name(Collocation) - Used specifically for strategy headers to avoid redundancy with parameter display - Handles both DataType and UnionAll types -See also: [`_strategy_type_name`](@ref), [`describe`](@ref) +See also: [`CTBase.Strategies._strategy_type_name`](@ref), [`CTBase.Strategies.describe`](@ref) """ function _strategy_base_name(T::DataType) return string(T.name.name) diff --git a/src/Strategies/contract/abstract_strategy.jl b/src/Strategies/contract/abstract_strategy.jl index 956f9952..0135f12e 100644 --- a/src/Strategies/contract/abstract_strategy.jl +++ b/src/Strategies/contract/abstract_strategy.jl @@ -301,7 +301,7 @@ julia> modeler[:maxiter] # Alias - automatically resolved - All functionality (alias resolution, provenance tracking) is handled by StrategyOptions - Use `options(strategy)` for full access to OptionValue objects with source information -See also: [`options`](@ref), [`Base.haskey`](@ref), [`Base.keys`](@ref), [`CTBase.Strategies.StrategyOptions`](@extref) +See also: [`CTBase.Strategies.options`](@ref), [`Base.haskey`](@ref), [`Base.keys`](@ref), [`CTBase.Strategies.StrategyOptions`](@ref) """ function Base.getindex(strategy::AbstractStrategy, key::Symbol) return options(strategy)[key] @@ -340,7 +340,7 @@ false - This is syntactic sugar for `haskey(options(strategy), key)` - Aliases are automatically resolved to canonical names -See also: [`options`](@ref), [`Base.getindex`](@ref), [`Base.keys`](@ref), [`CTBase.Strategies.StrategyOptions`](@extref) +See also: [`CTBase.Strategies.options`](@ref), [`Base.getindex`](@ref), [`Base.keys`](@ref), [`CTBase.Strategies.StrategyOptions`](@ref) """ function Base.haskey(strategy::AbstractStrategy, key::Symbol) return haskey(options(strategy), key) @@ -372,7 +372,7 @@ julia> collect(keys(modeler)) - This is syntactic sugar for `keys(options(strategy))` - Returns canonical names only (not aliases) -See also: [`options`](@ref), [`Base.getindex`](@ref), [`Base.haskey`](@ref), [`CTBase.Strategies.StrategyOptions`](@extref) +See also: [`CTBase.Strategies.options`](@ref), [`Base.getindex`](@ref), [`Base.haskey`](@ref), [`CTBase.Strategies.StrategyOptions`](@ref) """ function Base.keys(strategy::AbstractStrategy) return keys(options(strategy)) @@ -566,7 +566,7 @@ description(::Type{<:Modelers.ADNLP}) = "NLP modeler using ADNLPModels.\\nSee: https://jso.dev/ADNLPModels.jl" ``` -See also: [`describe`](@ref), [`AbstractStrategy`](@ref) +See also: [`CTBase.Strategies.describe`](@ref), [`CTBase.Strategies.AbstractStrategy`](@ref) """ description(::Type{<:AbstractStrategy}) = nothing diff --git a/src/Strategies/contract/parameters.jl b/src/Strategies/contract/parameters.jl index 10db27ac..d9c3efff 100644 --- a/src/Strategies/contract/parameters.jl +++ b/src/Strategies/contract/parameters.jl @@ -242,7 +242,7 @@ julia> description(GPU) "GPU-based computation" \`\`\` -See also: [`id`](@ref), [`AbstractStrategyParameter`](@ref) +See also: [`CTBase.Strategies.id`](@ref), [`CTBase.Strategies.AbstractStrategyParameter`](@ref) """ function description(parameter_type::Type{<:AbstractStrategyParameter}) throw( @@ -297,7 +297,7 @@ CPU (parameter) └─ description: CPU-based computation \`\`\` -See also: [`describe(::Symbol, ::StrategyRegistry)`](@ref), [`id`](@ref), [`description`](@ref) +See also: [`CTBase.Strategies.describe(::Symbol, ::StrategyRegistry)`](@ref), [`CTBase.Strategies.id`](@ref), [`CTBase.Strategies.description`](@ref) """ function describe(parameter_type::Type{T}) where {T<:AbstractStrategyParameter} describe(stdout, parameter_type) @@ -308,7 +308,7 @@ $(TYPEDSIGNATURES) Display parameter information to a specific IO stream. -See [`describe(::Type{<:AbstractStrategyParameter})`](@ref) for details. +See [`CTBase.Strategies.describe(::Type{<:AbstractStrategyParameter})`](@ref) for details. """ function describe(io::IO, parameter_type::Type{T}) where {T<:AbstractStrategyParameter} fmt = Core.get_format_codes(io) diff --git a/src/Traits/time_dependence.jl b/src/Traits/time_dependence.jl index 311a1d69..1d02535b 100644 --- a/src/Traits/time_dependence.jl +++ b/src/Traits/time_dependence.jl @@ -15,7 +15,7 @@ control problem, a vector field, a Hamiltonian). Used as a type parameter to distinguish between autonomous and non-autonomous objects at the type level, enabling dispatch and compile-time optimisations. -See also: [`Autonomous`](@ref), [`NonAutonomous`](@ref). +See also: [`CTBase.Traits.Autonomous`](@ref), [`CTBase.Traits.NonAutonomous`](@ref). """ abstract type TimeDependence end @@ -26,7 +26,7 @@ Type tag indicating that the dynamics and other functions do not explicitly depend on time. For autonomous systems, the dynamics have the form `ẋ = f(x, u)` rather than `ẋ = f(t, x, u)`. -See also: [`TimeDependence`](@ref), [`NonAutonomous`](@ref). +See also: [`CTBase.Traits.TimeDependence`](@ref), [`CTBase.Traits.NonAutonomous`](@ref). """ abstract type Autonomous <: TimeDependence end @@ -36,7 +36,7 @@ $(TYPEDEF) Type tag indicating that the dynamics and other functions explicitly depend on time. For non-autonomous systems, the dynamics have the form `ẋ = f(t, x, u)`. -See also: [`TimeDependence`](@ref), [`Autonomous`](@ref). +See also: [`CTBase.Traits.TimeDependence`](@ref), [`CTBase.Traits.Autonomous`](@ref). """ abstract type NonAutonomous <: TimeDependence end @@ -60,7 +60,7 @@ for better error messages. - `obj::Any`: The object to check. # Throws -- [`CTBase.Exceptions.IncorrectArgument`](@extref): Always, indicating the object does not have the trait. +- [`CTBase.Exceptions.IncorrectArgument`](@ref): Always, indicating the object does not have the trait. See also: [`CTBase.Traits.TimeDependence`](@ref), [`CTBase.Traits.time_dependence`](@ref). """ @@ -86,7 +86,7 @@ to return the specific trait value (`Autonomous` or `NonAutonomous`). - `obj::Any`: The object to query. # Throws -- [`CTBase.Exceptions.NotImplemented`](@extref): Always, indicating the method must be implemented. +- [`CTBase.Exceptions.NotImplemented`](@ref): Always, indicating the method must be implemented. See also: [`CTBase.Traits.TimeDependence`](@ref), [`CTBase.Traits.has_time_dependence_trait`](@ref). """ @@ -115,8 +115,8 @@ if `time_dependence(obj)` is `Autonomous`. - `Bool`: true if the object is autonomous. # Throws -- [`CTBase.Exceptions.IncorrectArgument`](@extref): If the object does not support time-dependence queries. -- [`CTBase.Exceptions.NotImplemented`](@extref): If `time_dependence` is not implemented for the object type. +- [`CTBase.Exceptions.IncorrectArgument`](@ref): If the object does not support time-dependence queries. +- [`CTBase.Exceptions.NotImplemented`](@ref): If `time_dependence` is not implemented for the object type. See also: [`CTBase.Traits.TimeDependence`](@ref), [`CTBase.Traits.time_dependence`](@ref). """ @@ -140,8 +140,8 @@ if `time_dependence(obj)` is `NonAutonomous`. - `Bool`: true if the object is non-autonomous. # Throws -- [`CTBase.Exceptions.IncorrectArgument`](@extref): If the object does not support time-dependence queries. -- [`CTBase.Exceptions.NotImplemented`](@extref): If `time_dependence` is not implemented for the object type. +- [`CTBase.Exceptions.IncorrectArgument`](@ref): If the object does not support time-dependence queries. +- [`CTBase.Exceptions.NotImplemented`](@ref): If `time_dependence` is not implemented for the object type. See also: [`CTBase.Traits.TimeDependence`](@ref), [`CTBase.Traits.time_dependence`](@ref). """ diff --git a/src/Traits/variable_dependence.jl b/src/Traits/variable_dependence.jl index ea1a6120..d83aa5f9 100644 --- a/src/Traits/variable_dependence.jl +++ b/src/Traits/variable_dependence.jl @@ -76,7 +76,7 @@ for better error messages. - `obj::Any`: The object to check. # Throws -- [`CTBase.Exceptions.IncorrectArgument`](@extref): Always, indicating the object does not have the trait. +- [`CTBase.Exceptions.IncorrectArgument`](@ref): Always, indicating the object does not have the trait. See also: [`CTBase.Traits.VariableDependence`](@ref), [`CTBase.Traits.variable_dependence`](@ref). """ @@ -102,7 +102,7 @@ to return the specific trait value (`Fixed` or `NonFixed`). - `obj::Any`: The object to query. # Throws -- [`CTBase.Exceptions.NotImplemented`](@extref): Always, indicating the method must be implemented. +- [`CTBase.Exceptions.NotImplemented`](@ref): Always, indicating the method must be implemented. See also: [`CTBase.Traits.VariableDependence`](@ref), [`CTBase.Traits.has_variable_dependence_trait`](@ref). """ @@ -135,8 +135,8 @@ if `variable_dependence(obj)` is `NonFixed`. - `Bool`: true if the object depends on variable parameters. # Throws -- [`CTBase.Exceptions.IncorrectArgument`](@extref): If the object does not support variable-dependence queries. -- [`CTBase.Exceptions.NotImplemented`](@extref): If `variable_dependence` is not implemented for the object type. +- [`CTBase.Exceptions.IncorrectArgument`](@ref): If the object does not support variable-dependence queries. +- [`CTBase.Exceptions.NotImplemented`](@ref): If `variable_dependence` is not implemented for the object type. See also: [`CTBase.Traits.VariableDependence`](@ref), [`CTBase.Traits.variable_dependence`](@ref). """ @@ -160,8 +160,8 @@ if `variable_dependence(obj)` is `Fixed`. - `Bool`: true if the object does not depend on variable parameters. # Throws -- [`CTBase.Exceptions.IncorrectArgument`](@extref): If the object does not support variable-dependence queries. -- [`CTBase.Exceptions.NotImplemented`](@extref): If `variable_dependence` is not implemented for the object type. +- [`CTBase.Exceptions.IncorrectArgument`](@ref): If the object does not support variable-dependence queries. +- [`CTBase.Exceptions.NotImplemented`](@ref): If `variable_dependence` is not implemented for the object type. See also: [`CTBase.Traits.VariableDependence`](@ref), [`CTBase.Traits.variable_dependence`](@ref). """ @@ -185,8 +185,8 @@ if `variable_dependence(obj)` is `NonFixed`. - `Bool`: true if the object depends on variable parameters. # Throws -- [`CTBase.Exceptions.IncorrectArgument`](@extref): If the object does not support variable-dependence queries. -- [`CTBase.Exceptions.NotImplemented`](@extref): If `variable_dependence` is not implemented for the object type. +- [`CTBase.Exceptions.IncorrectArgument`](@ref): If the object does not support variable-dependence queries. +- [`CTBase.Exceptions.NotImplemented`](@ref): If `variable_dependence` is not implemented for the object type. See also: `is_variable`, [`CTBase.Traits.VariableDependence`](@ref). """ From 8193b52828cb160bc2a01538762d3c3ec10d5e30 Mon Sep 17 00:00:00 2001 From: Olivier Cots Date: Tue, 23 Jun 2026 16:16:03 +0200 Subject: [PATCH 6/6] Remove CTFlows references and fix docstring compliance in Traits module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove CTFlows.Configs references from trait docstrings and examples - Change @extref to @ref for internal Exceptions symbols - Update documentation (getting-started, guide/traits, index) - Clean up trait examples to remove CTFlows-specific configuration references - Part of CTFlows→CTBase migration --- docs/src/getting-started.md | 4 ++- docs/src/guide/traits.md | 61 ++++++++++++++++++++++++++----------- docs/src/index.md | 2 ++ src/Traits/Traits.jl | 58 ++++++++++++++++++++++++----------- src/Traits/abstract.jl | 27 +++++----------- src/Traits/ad.jl | 4 +-- src/Traits/dynamics.jl | 20 +++--------- src/Traits/mode.jl | 16 ++-------- src/Traits/mutability.jl | 12 ++++---- 9 files changed, 112 insertions(+), 92 deletions(-) diff --git a/docs/src/getting-started.md b/docs/src/getting-started.md index 84218a26..029e4536 100644 --- a/docs/src/getting-started.md +++ b/docs/src/getting-started.md @@ -31,10 +31,11 @@ Three things to keep in mind: CTBase.Exceptions.NotImplemented ``` 2. **Submodule-first API.** The public API lives in named submodules - (`Descriptions`, `Exceptions`, `DevTools`, `Core`, `Unicode`). + (`Core`, `Descriptions`, `Exceptions`, `Traits`, `DevTools`, `Unicode`, …). You can bring a submodule's exports into scope explicitly: ```julia using CTBase.Exceptions # brings IncorrectArgument, NotImplemented, … into scope + using CTBase.Traits # brings Autonomous, NonAutonomous, is_autonomous, … into scope ``` 3. **Extension-backed features.** `run_tests`, `postprocess_coverage`, and `automatic_reference_documentation` require loading the matching weak dependency @@ -111,6 +112,7 @@ For more, see the **[Exceptions guide](guide/exceptions.md)**. | :--- | :--- | | Descriptions catalogue and completion | [Descriptions](guide/descriptions.md) | | Exception hierarchy and best practices | [Exceptions](guide/exceptions.md) | +| Compile-time traits and dispatch | [Traits](guide/traits.md) | | Modular test runner setup | [Test Runner](guide/test-runner.md) | | Coverage report generation | [Coverage](guide/coverage.md) | | Auto-generated API reference | [API Documentation](guide/api-documentation.md) | diff --git a/docs/src/guide/traits.md b/docs/src/guide/traits.md index 8a9710c4..cfa0e799 100644 --- a/docs/src/guide/traits.md +++ b/docs/src/guide/traits.md @@ -5,8 +5,8 @@ CurrentModule = CTBase ``` [`CTBase.Traits`](@ref CTBase.Traits) provides a small set of **compile-time -traits** shared across the control-toolbox ecosystem. Traits are empty marker -types used as type parameters (or returned by accessor functions) so that +traits** shared across the control-toolbox ecosystem. A trait is an abstract type +used as a **type parameter** or returned by an accessor function so that behaviour can be selected by dispatch, with **no runtime cost**. ```@repl traits @@ -14,9 +14,10 @@ using CTBase import CTBase.Traits ``` -Downstream packages use these traits to encode, for example, the **call -signature** of a vector field or Hamiltonian, and to dispatch system builders -without runtime branches. +A typical use case is encoding a property of a callable object — does it take a +time argument? does it depend on an extra variable? is it evaluated in-place? — +so that a wrapper type can select the correct call path at compile time, without +runtime conditionals. ## Trait families @@ -30,8 +31,8 @@ Does the object depend on time ``t``? | [`Traits.NonAutonomous`](@ref CTBase.Traits.NonAutonomous) | ``t`` must be supplied | Both are abstract subtypes of [`Traits.TimeDependence`](@ref CTBase.Traits.TimeDependence). -They are used as the time-dependence type parameter of `CTModels.Model` and of -CTFlows data wrappers. +Because they are abstract, they can only appear as type parameters — they are not +instantiated, only dispatched upon. ```@repl traits Traits.Autonomous <: Traits.TimeDependence @@ -48,6 +49,8 @@ design variable)? | [`Traits.Fixed`](@ref CTBase.Traits.Fixed) | no ``v`` argument | | [`Traits.NonFixed`](@ref CTBase.Traits.NonFixed) | ``v`` must be supplied | +Both are concrete subtypes of [`Traits.VariableDependence`](@ref CTBase.Traits.VariableDependence): + ```@repl traits Traits.Fixed <: Traits.VariableDependence Traits.NonFixed <: Traits.VariableDependence @@ -64,6 +67,10 @@ Does a function allocate a new output, or write into a pre-allocated buffer? ### Other families +These traits encode properties that are fixed at construction time and carried +as type parameters. They are not opted into via the two-method contract described +below — they are passed directly as type arguments. + | Family | Values | |---|---| | Integration mode | [`Traits.EndPointMode`](@ref CTBase.Traits.EndPointMode), [`Traits.TrajectoryMode`](@ref CTBase.Traits.TrajectoryMode) | @@ -79,7 +86,7 @@ A type opts in to a trait by implementing **two methods**: one declaring that it [`Traits.is_variable`](@ref CTBase.Traits.is_variable), …) then follow generically — they are not implemented per type. -For time dependence, implement `has_time_dependence_trait` and `time_dependence`: +For time and variable dependence: ```@repl traits struct MyObject end @@ -91,24 +98,40 @@ Traits.has_variable_dependence_trait(::MyObject) = true Traits.variable_dependence(::MyObject) = Traits.Fixed obj = MyObject() -Traits.is_autonomous(obj) # false (derived from time_dependence) -Traits.is_nonautonomous(obj) # true -Traits.is_variable(obj) # false (derived from variable_dependence) -Traits.is_nonvariable(obj) # true +Traits.is_autonomous(obj) +Traits.is_nonautonomous(obj) +Traits.is_variable(obj) +Traits.is_nonvariable(obj) +``` + +For mutability, the same pattern applies with `has_mutability_trait` and `mutability`: + +```@repl traits +struct MyMutableObject end + +Traits.has_mutability_trait(::MyMutableObject) = true +Traits.mutability(::MyMutableObject) = Traits.InPlace + +Traits.is_inplace(MyMutableObject()) +Traits.is_outofplace(MyMutableObject()) ``` If a type does not declare a trait, the predicates throw an informative error rather than returning a wrong default: ```@repl traits +try # hide Traits.is_autonomous(3.14) +catch e # hide +showerror(IOContext(stdout, :color => false), e) # hide +end # hide ``` -!!! note "Single source of truth" - `Traits.Autonomous` / `Traits.NonAutonomous` are the very types used as the - `CTModels.Model` time-dependence parameter, so `Traits.time_dependence(model)` - and `Traits.is_autonomous(model)` work out of the box on a real optimal - control problem. +!!! note "Trait types are shared" + Because trait types (e.g. `Traits.Autonomous`) are defined in a single place, + a type that carries `Traits.Autonomous` as a type parameter and an object that + implements `time_dependence` returning `Traits.Autonomous` are compatible by + construction — no conversion or mapping needed. ## Accessor / predicate summary @@ -120,3 +143,7 @@ Traits.is_autonomous(3.14) | [`Traits.ad_trait`](@ref CTBase.Traits.ad_trait) | — | | [`Traits.variable_costate_trait`](@ref CTBase.Traits.variable_costate_trait) | — | | [`Traits.dynamics_trait`](@ref CTBase.Traits.dynamics_trait) | — | + +## See Also + +- [Exceptions guide](exceptions.md) — understanding `IncorrectArgument` and `NotImplemented`. diff --git a/docs/src/index.md b/docs/src/index.md index 0ff490de..cca940d1 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -27,6 +27,7 @@ It provides the **base layer** shared by all packages: common types, structured | [`CTBase.Core`](@ref) | Fundamental numeric type alias (`ctNumber`) and internal display helpers | | [`CTBase.Descriptions`](@ref) | Symbolic description tuples: catalogue management, pattern completion, similarity search | | [`CTBase.Exceptions`](@ref) | Typed exception hierarchy with rich context fields | +| [`CTBase.Traits`](@ref) | Compile-time trait types for time dependence, variable dependence, mutability, and dynamics dispatch | | [`CTBase.DevTools`](@ref) | Developer tools with tag-based dispatch for `run_tests`, `postprocess_coverage`, and `automatic_reference_documentation` | | [`CTBase.Unicode`](@ref) | Unicode subscript/superscript helpers for display | @@ -35,6 +36,7 @@ It provides the **base layer** shared by all packages: common types, structured - **[Getting Started](getting-started.md)** — installation, mental model, 5-minute walkthrough. - **[Descriptions](guide/descriptions.md)** — catalogue API, pattern matching, error handling. - **[Exceptions](guide/exceptions.md)** — exception hierarchy, choosing the right type, best practices. +- **[Traits](guide/traits.md)** — compile-time trait types, the opt-in contract, and predicate functions. - **[Test Runner](guide/test-runner.md)** — modular test infrastructure with `CTBase.DevTools.run_tests`. - **[Coverage](guide/coverage.md)** — post-processing coverage artifacts with `CTBase.postprocess_coverage`. - **[API Documentation](guide/api-documentation.md)** — auto-generating per-module API pages. diff --git a/src/Traits/Traits.jl b/src/Traits/Traits.jl index dacb3e1c..d8ac501f 100644 --- a/src/Traits/Traits.jl +++ b/src/Traits/Traits.jl @@ -1,23 +1,47 @@ """ Traits -Trait types and trait-based dispatch shared across the control-toolbox ecosystem. - -This module provides the trait system used for compile-time dispatch on: -- Time dependence: [`Autonomous`](@ref), [`NonAutonomous`](@ref) -- Variable dependence: [`Fixed`](@ref), [`NonFixed`](@ref) -- Integration mode: [`EndPointMode`](@ref), [`TrajectoryMode`](@ref) -- Dynamics type: [`StateDynamics`](@ref), [`HamiltonianDynamics`](@ref), [`AugmentedHamiltonianDynamics`](@ref) -- Mutability: [`InPlace`](@ref), [`OutOfPlace`](@ref) -- Automatic differentiation: [`WithAD`](@ref), [`WithoutAD`](@ref) -- Variable costate capability: [`SupportsVariableCostate`](@ref), [`NoVariableCostate`](@ref) - -Traits are used as type parameters in configuration types, vector fields, and systems -to enable static dispatch without runtime type checks. - -The time-dependence trait types (`TimeDependence`, `Autonomous`, `NonAutonomous`) -historically lived in `CTModels.Components`; they are now defined here so the whole -ecosystem shares a single set of types (CTModels consumes them from here). +Compile-time trait types and trait-based dispatch utilities. + +Traits are abstract or empty concrete types used as type parameters or returned +by accessor functions. Behaviour is selected by dispatch at compile time, with +no runtime cost. + +# Organization + +- **abstract.jl**: Root abstract type `AbstractTrait` and family abstractions +- **time_dependence.jl**: Time-dependence traits and the opt-in contract +- **variable_dependence.jl**: Variable-dependence traits and the opt-in contract +- **mutability.jl**: Mutability traits and the opt-in contract +- **mode.jl**: Integration-mode traits (`EndPointMode`, `TrajectoryMode`) +- **dynamics.jl**: Dynamics-type traits (`StateDynamics`, `HamiltonianDynamics`, `AugmentedHamiltonianDynamics`) +- **ad.jl**: Automatic-differentiation traits (`WithAD`, `WithoutAD`) +- **variable_costate.jl**: Variable-costate traits (`SupportsVariableCostate`, `NoVariableCostate`) +- **helpers.jl**: Internal utility (`_caller_function_name`) + +# Public API + +## Trait families + +- **Time dependence**: `TimeDependence`, `Autonomous`, `NonAutonomous` +- **Variable dependence**: `VariableDependence`, `Fixed`, `NonFixed` +- **Mutability**: `InPlace`, `OutOfPlace` +- **Integration mode**: `EndPointMode`, `TrajectoryMode` +- **Dynamics**: `StateDynamics`, `HamiltonianDynamics`, `AugmentedHamiltonianDynamics` +- **Automatic differentiation**: `WithAD`, `WithoutAD` +- **Variable costate**: `SupportsVariableCostate`, `NoVariableCostate` + +## Trait contract + +For time-dependence, variable-dependence, and mutability, a type opts in by +implementing two methods — `has__trait` returning `true`, and an accessor +(`time_dependence`, `variable_dependence`, `mutability`) returning the trait type. +Boolean predicates (`is_autonomous`, `is_variable`, `is_inplace`, …) are then +derived generically. + +The remaining families (`EndPointMode`, `StateDynamics`, `WithAD`, +`SupportsVariableCostate`) are used as type parameters only and do not use the +two-method contract. """ module Traits diff --git a/src/Traits/abstract.jl b/src/Traits/abstract.jl index d405f927..9a2e9cf3 100644 --- a/src/Traits/abstract.jl +++ b/src/Traits/abstract.jl @@ -1,29 +1,20 @@ """ $(TYPEDEF) -Abstract base type for trait markers in CTFlows. +Abstract base type for all trait markers. -Traits are empty marker types used as type parameters to encode configuration -properties at compile time. Unlike tags (which mark extension implementations), -traits encode semantic properties of the configuration itself (e.g., integration -mode, content type, mutability). - -# Trait Pattern - -Traits are used as type parameters in abstract configuration types to enable -compile-time dispatch without runtime type checks. For example, `AbstractConfig` -uses `EndPointMode` vs `TrajectoryMode` to distinguish integration modes, and -`StateDynamics` vs `HamiltonianDynamics` to distinguish dynamics types. - -All concrete trait types are empty structs with no fields, making them zero-cost -at runtime. +Traits are empty marker types used as type parameters to encode properties at +compile time. Unlike tags (which mark extension implementations), traits encode +semantic properties of an object (e.g., integration mode, dynamics type, +mutability). All concrete trait types are empty structs with no fields, making +them zero-cost at runtime. # Interface Requirements Concrete trait subtypes should: - Be empty structs with no fields (pure markers) - Subtype an intermediate abstract trait category (e.g., `AbstractModeTrait`) -- Be used as type parameters in configuration types +- Be used as type parameters or returned by accessor functions # Example \`\`\`julia-repl @@ -34,10 +25,6 @@ true julia> EndPointMode <: Traits.AbstractModeTrait true - -julia> # Used as type parameters in configs: -julia> StateEndPointConfig <: CTFlows.Configs.AbstractConfig{<:Any, EndPointMode, StateDynamics} -true \`\`\` # Notes diff --git a/src/Traits/ad.jl b/src/Traits/ad.jl index 2e1a1f60..d187beba 100644 --- a/src/Traits/ad.jl +++ b/src/Traits/ad.jl @@ -31,7 +31,7 @@ true - `WithoutAD` indicates the system uses pre-computed derivatives or manual implementations - The specific meaning depends on the system type and context -See also: [`CTBase.Traits.WithAD`](@ref), [`CTBase.Traits.WithoutAD`](@ref), [`CTBase.Core.AbstractCache`](@ref). +See also: [`CTBase.Traits.WithAD`](@ref), [`CTBase.Traits.WithoutAD`](@ref), `CTBase.Core.AbstractCache`. """ abstract type AbstractADTrait <: AbstractTrait end @@ -66,7 +66,7 @@ true - The cache is passed through parameters during integration or evaluation - The specific operations enabled depend on the system type and AD backend -See also: [`CTBase.Traits.AbstractADTrait`](@ref), [`CTBase.Traits.WithoutAD`](@ref), [`CTBase.Core.AbstractCache`](@ref). +See also: [`CTBase.Traits.AbstractADTrait`](@ref), [`CTBase.Traits.WithoutAD`](@ref), `CTBase.Core.AbstractCache`. """ struct WithAD <: AbstractADTrait end # system carries H + AD backend diff --git a/src/Traits/dynamics.jl b/src/Traits/dynamics.jl index deb90c08..57a20b40 100644 --- a/src/Traits/dynamics.jl +++ b/src/Traits/dynamics.jl @@ -16,18 +16,13 @@ true julia> HamiltonianDynamics <: Traits.AbstractDynamicsTrait true - -julia> # Used in configuration type parameters: -julia> StateEndPointConfig <: CTFlows.Configs.AbstractConfig{<:Any, <:Traits.AbstractModeTrait, StateDynamics} -true \`\`\` # Notes -- Dynamics traits are used as the third type parameter in `AbstractConfigWithMaC` - State dynamics indicates configurations with only state variables (no costate) - Hamiltonian dynamics indicates configurations with both state and costate variables -See also: [`CTBase.Traits.StateDynamics`](@ref), [`CTBase.Traits.HamiltonianDynamics`](@ref), [`CTFlows.Configs.AbstractConfig`](@ref). +See also: [`CTBase.Traits.StateDynamics`](@ref), [`CTBase.Traits.HamiltonianDynamics`](@ref). """ abstract type AbstractDynamicsTrait <: AbstractTrait end @@ -49,9 +44,6 @@ StateDynamics() julia> st isa Traits.AbstractDynamicsTrait true -julia> # Used in state-only configurations: -julia> StateEndPointConfig <: CTFlows.Configs.AbstractConfig{<:Any, <:Traits.AbstractModeTrait, StateDynamics} -true \`\`\` # Notes @@ -59,7 +51,7 @@ true - The `initial_costate` accessor throws a `PreconditionError` for state configurations - This mode is suitable for standard ODE integration without adjoint variables -See also: [`CTBase.Traits.HamiltonianDynamics`](@ref), [`CTBase.Traits.AbstractDynamicsTrait`](@ref), [`CTFlows.Configs.StateEndPointConfig`](@ref). +See also: [`CTBase.Traits.HamiltonianDynamics`](@ref), [`CTBase.Traits.AbstractDynamicsTrait`](@ref). """ struct StateDynamics <: AbstractDynamicsTrait end @@ -81,9 +73,6 @@ HamiltonianDynamics() julia> ham isa Traits.AbstractDynamicsTrait true -julia> # Used in Hamiltonian configurations: -julia> HamiltonianEndPointConfig <: CTFlows.Configs.AbstractConfig{<:Any, <:Traits.AbstractModeTrait, HamiltonianDynamics} -true \`\`\` # Notes @@ -91,7 +80,7 @@ true - The `initial_condition` accessor returns `vcat(x0, p0)` for Hamiltonian configurations - This mode is suitable for optimal control problems with Pontryagin's maximum principle -See also: [`CTBase.Traits.StateDynamics`](@ref), [`CTBase.Traits.AbstractDynamicsTrait`](@ref), [`CTFlows.Configs.HamiltonianEndPointConfig`](@ref). +See also: [`CTBase.Traits.StateDynamics`](@ref), [`CTBase.Traits.AbstractDynamicsTrait`](@ref). """ struct HamiltonianDynamics <: AbstractDynamicsTrait end @@ -101,11 +90,10 @@ $(TYPEDEF) Trait marker for augmented Hamiltonian dynamics, where the Hamiltonian includes an augmented variable (e.g., a parameter or control variable) in addition to state and costate variables. # Notes -- Used in conjunction with [`CTFlows.Configs.AbstractAugmentedHamiltonianConfig`](@ref) to specify that a configuration is for an augmented Hamiltonian system. - Subtypes [`CTBase.Traits.AbstractDynamicsTrait`](@ref). - Used to distinguish augmented Hamiltonian systems from standard Hamiltonian systems in trait-based dispatch. -See also: [`CTBase.Traits.HamiltonianDynamics`](@ref), [`CTFlows.Configs.AbstractAugmentedHamiltonianConfig`](@ref), [`CTBase.Traits.AbstractDynamicsTrait`](@ref). +See also: [`CTBase.Traits.HamiltonianDynamics`](@ref), [`CTBase.Traits.AbstractDynamicsTrait`](@ref). """ struct AugmentedHamiltonianDynamics <: AbstractDynamicsTrait end diff --git a/src/Traits/mode.jl b/src/Traits/mode.jl index f40d350c..21a36cf9 100644 --- a/src/Traits/mode.jl +++ b/src/Traits/mode.jl @@ -17,17 +17,13 @@ true julia> TrajectoryMode <: Traits.AbstractModeTrait true -julia> # Used in configuration type parameters: -julia> StateEndPointConfig <: CTFlows.Configs.AbstractConfig{<:Any, EndPointMode, <:Traits.AbstractDynamicsTrait} -true \`\`\` # Notes -- Mode traits are used as the second type parameter in `AbstractConfigWithMaC` - Point mode indicates integration from a single initial condition to a specific final time - Trajectory mode indicates integration over a continuous time interval -See also: [`CTBase.Traits.EndPointMode`](@ref), [`CTBase.Traits.TrajectoryMode`](@ref), [`CTFlows.Configs.AbstractConfig`](@ref). +See also: [`CTBase.Traits.EndPointMode`](@ref), [`CTBase.Traits.TrajectoryMode`](@ref). """ abstract type AbstractModeTrait <: AbstractTrait end @@ -49,9 +45,6 @@ EndPointMode() julia> pt isa Traits.AbstractModeTrait true -julia> # Used in point-to-point configurations: -julia> StateEndPointConfig <: CTFlows.Configs.AbstractConfig{<:Any, EndPointMode, <:Traits.AbstractDynamicsTrait} -true \`\`\` # Notes @@ -59,7 +52,7 @@ true - This mode is suitable for boundary value problems and shooting methods - The `tspan` accessor returns `(c.t0, c.tf)` for point configurations -See also: [`CTBase.Traits.TrajectoryMode`](@ref), [`CTBase.Traits.AbstractModeTrait`](@ref), [`CTFlows.Configs.StateEndPointConfig`](@ref). +See also: [`CTBase.Traits.TrajectoryMode`](@ref), [`CTBase.Traits.AbstractModeTrait`](@ref). """ struct EndPointMode <: AbstractModeTrait end @@ -81,9 +74,6 @@ TrajectoryMode() julia> traj isa Traits.AbstractModeTrait true -julia> # Used in trajectory configurations: -julia> StateTrajectoryConfig <: CTFlows.Configs.AbstractConfig{<:Any, TrajectoryMode, <:Traits.AbstractDynamicsTrait} -true \`\`\` # Notes @@ -91,6 +81,6 @@ true - This mode is suitable for generating full time evolution and visualization - The `tspan` accessor returns `c.tspan` directly for trajectory configurations -See also: [`CTBase.Traits.EndPointMode`](@ref), [`CTBase.Traits.AbstractModeTrait`](@ref), [`CTFlows.Configs.StateTrajectoryConfig`](@ref). +See also: [`CTBase.Traits.EndPointMode`](@ref), [`CTBase.Traits.AbstractModeTrait`](@ref). """ struct TrajectoryMode <: AbstractModeTrait end diff --git a/src/Traits/mutability.jl b/src/Traits/mutability.jl index 89bef4f5..5c000f99 100644 --- a/src/Traits/mutability.jl +++ b/src/Traits/mutability.jl @@ -89,7 +89,7 @@ for better error messages. - `obj::Any`: The object to check. # Throws -- [`CTBase.Exceptions.IncorrectArgument`](@extref): Always, indicating the object does not have the trait. +- [`CTBase.Exceptions.IncorrectArgument`](@ref): Always, indicating the object does not have the trait. See also: [`CTBase.Traits.AbstractMutabilityTrait`](@ref), [`CTBase.Traits.mutability`](@ref). """ @@ -115,7 +115,7 @@ to return the specific trait value (`InPlace` or `OutOfPlace`). - `obj::Any`: The object to query. # Throws -- [`CTBase.Exceptions.NotImplemented`](@extref): Always, indicating the method must be implemented. +- [`CTBase.Exceptions.NotImplemented`](@ref): Always, indicating the method must be implemented. See also: [`CTBase.Traits.AbstractMutabilityTrait`](@ref), [`CTBase.Traits.has_mutability_trait`](@ref). """ @@ -144,8 +144,8 @@ if `mutability(obj)` is `InPlace`. - `Bool`: true if the object uses in-place evaluation. # Throws -- [`CTBase.Exceptions.IncorrectArgument`](@extref): If the object does not support mutability queries. -- [`CTBase.Exceptions.NotImplemented`](@extref): If `mutability` is not implemented for the object type. +- [`CTBase.Exceptions.IncorrectArgument`](@ref): If the object does not support mutability queries. +- [`CTBase.Exceptions.NotImplemented`](@ref): If `mutability` is not implemented for the object type. See also: [`CTBase.Traits.AbstractMutabilityTrait`](@ref), [`CTBase.Traits.mutability`](@ref). """ @@ -169,8 +169,8 @@ if `mutability(obj)` is `OutOfPlace`. - `Bool`: true if the object uses out-of-place evaluation. # Throws -- [`CTBase.Exceptions.IncorrectArgument`](@extref): If the object does not support mutability queries. -- [`CTBase.Exceptions.NotImplemented`](@extref): If `mutability` is not implemented for the object type. +- [`CTBase.Exceptions.IncorrectArgument`](@ref): If the object does not support mutability queries. +- [`CTBase.Exceptions.NotImplemented`](@ref): If `mutability` is not implemented for the object type. See also: [`CTBase.Traits.AbstractMutabilityTrait`](@ref), [`CTBase.Traits.mutability`](@ref). """