Skip to content

Commit ef69344

Browse files
authored
Merge pull request #461 from control-toolbox/move/ctflows-to-ctbase-phase-b
Add CTBase.Traits submodule (phase B of CTFlows→CTBase move)
2 parents a30a895 + 8193b52 commit ef69344

31 files changed

Lines changed: 2457 additions & 21 deletions

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "CTBase"
22
uuid = "54762871-cc72-4466-b8e8-f6c8b58076cd"
3-
version = "0.21.1-beta"
3+
version = "0.22.0-beta"
44
authors = ["Olivier Cots <olivier.cots@irit.fr>", "Jean-Baptiste Caillau <caillau@univ-cotedazur.fr>"]
55

66
[deps]

docs/MIGRATION.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,34 @@ let ctOutDir = ''
153153

154154
And reference them in `head` using `${baseTemp.base}assets/...` instead of the remote URLs.
155155

156+
#### Simplify nav configuration
157+
158+
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:
159+
160+
Replace:
161+
162+
```typescript
163+
const navTemp = {
164+
nav: 'REPLACE_ME_DOCUMENTER_VITEPRESS',
165+
}
166+
167+
const nav = [
168+
...navTemp.nav,
169+
{
170+
component: 'VersionPicker'
171+
}
172+
]
173+
```
174+
175+
With:
176+
177+
```typescript
178+
const nav = [
179+
{ text: 'Home', link: '/index' },
180+
{component: 'VersionPicker'}
181+
]
182+
```
183+
156184
### 6. Install npm dependencies
157185

158186
```bash

docs/api_reference.jl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,13 @@ function generate_api_reference(src_dir::String)
4242
joinpath("Interpolation", "Interpolation.jl"), joinpath("Interpolation", "types.jl"),
4343
joinpath("Interpolation", "ctinterpolate.jl"), joinpath("Interpolation", "display.jl"),
4444
)),
45+
(mod=CTBase.Traits, title="Traits", filename="traits", files=src(
46+
joinpath("Traits", "Traits.jl"), joinpath("Traits", "helpers.jl"),
47+
joinpath("Traits", "abstract.jl"), joinpath("Traits", "mode.jl"),
48+
joinpath("Traits", "dynamics.jl"), joinpath("Traits", "ad.jl"),
49+
joinpath("Traits", "variable_costate.jl"), joinpath("Traits", "mutability.jl"),
50+
joinpath("Traits", "time_dependence.jl"), joinpath("Traits", "variable_dependence.jl"),
51+
)),
4552
(mod=CTBase.Options, title="Options", filename="options", files=src(
4653
joinpath("Options", "Options.jl"), joinpath("Options", "not_provided.jl"),
4754
joinpath("Options", "option_value.jl"), joinpath("Options", "option_definition.jl"),

docs/make.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ with_api_reference(src_dir) do api_pages
7272
"Core Concepts" => [
7373
"Descriptions" => joinpath("guide", "descriptions.md"),
7474
"Exceptions" => joinpath("guide", "exceptions.md"),
75+
"Traits" => joinpath("guide", "traits.md"),
7576
],
7677
"Strategies & Options" => [
7778
"Options System" => joinpath("guide", "options-system.md"),

docs/src/.vitepress/config.mts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,9 @@ const baseTemp = {
1717
base: 'REPLACE_ME_DOCUMENTER_VITEPRESS',// TODO: replace this in makedocs!
1818
}
1919

20-
const navTemp = {
21-
nav: 'REPLACE_ME_DOCUMENTER_VITEPRESS',
22-
}
23-
2420
const nav = [
25-
...navTemp.nav,
26-
{
27-
component: 'VersionPicker'
28-
}
21+
{ text: 'Home', link: '/index' },
22+
{component: 'VersionPicker'}
2923
]
3024

3125
// https://vitepress.dev/reference/site-config

docs/src/getting-started.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,11 @@ Three things to keep in mind:
3131
CTBase.Exceptions.NotImplemented
3232
```
3333
2. **Submodule-first API.** The public API lives in named submodules
34-
(`Descriptions`, `Exceptions`, `DevTools`, `Core`, `Unicode`).
34+
(`Core`, `Descriptions`, `Exceptions`, `Traits`, `DevTools`, `Unicode`, …).
3535
You can bring a submodule's exports into scope explicitly:
3636
```julia
3737
using CTBase.Exceptions # brings IncorrectArgument, NotImplemented, … into scope
38+
using CTBase.Traits # brings Autonomous, NonAutonomous, is_autonomous, … into scope
3839
```
3940
3. **Extension-backed features.** `run_tests`, `postprocess_coverage`, and
4041
`automatic_reference_documentation` require loading the matching weak dependency
@@ -111,6 +112,7 @@ For more, see the **[Exceptions guide](guide/exceptions.md)**.
111112
| :--- | :--- |
112113
| Descriptions catalogue and completion | [Descriptions](guide/descriptions.md) |
113114
| Exception hierarchy and best practices | [Exceptions](guide/exceptions.md) |
115+
| Compile-time traits and dispatch | [Traits](guide/traits.md) |
114116
| Modular test runner setup | [Test Runner](guide/test-runner.md) |
115117
| Coverage report generation | [Coverage](guide/coverage.md) |
116118
| Auto-generated API reference | [API Documentation](guide/api-documentation.md) |

docs/src/guide/traits.md

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
# Traits: compile-time properties
2+
3+
```@meta
4+
CurrentModule = CTBase
5+
```
6+
7+
[`CTBase.Traits`](@ref CTBase.Traits) provides a small set of **compile-time
8+
traits** shared across the control-toolbox ecosystem. A trait is an abstract type
9+
used as a **type parameter** or returned by an accessor function so that
10+
behaviour can be selected by dispatch, with **no runtime cost**.
11+
12+
```@repl traits
13+
using CTBase
14+
import CTBase.Traits
15+
```
16+
17+
A typical use case is encoding a property of a callable object — does it take a
18+
time argument? does it depend on an extra variable? is it evaluated in-place? —
19+
so that a wrapper type can select the correct call path at compile time, without
20+
runtime conditionals.
21+
22+
## Trait families
23+
24+
### Time dependence
25+
26+
Does the object depend on time ``t``?
27+
28+
| Type | Meaning |
29+
|---|---|
30+
| [`Traits.Autonomous`](@ref CTBase.Traits.Autonomous) | ``t`` is not an argument |
31+
| [`Traits.NonAutonomous`](@ref CTBase.Traits.NonAutonomous) | ``t`` must be supplied |
32+
33+
Both are abstract subtypes of [`Traits.TimeDependence`](@ref CTBase.Traits.TimeDependence).
34+
Because they are abstract, they can only appear as type parameters — they are not
35+
instantiated, only dispatched upon.
36+
37+
```@repl traits
38+
Traits.Autonomous <: Traits.TimeDependence
39+
Traits.NonAutonomous <: Traits.TimeDependence
40+
```
41+
42+
### Variable dependence
43+
44+
Does the object depend on an extra parameter ``v`` (e.g. a free final time or a
45+
design variable)?
46+
47+
| Type | Meaning |
48+
|---|---|
49+
| [`Traits.Fixed`](@ref CTBase.Traits.Fixed) | no ``v`` argument |
50+
| [`Traits.NonFixed`](@ref CTBase.Traits.NonFixed) | ``v`` must be supplied |
51+
52+
Both are concrete subtypes of [`Traits.VariableDependence`](@ref CTBase.Traits.VariableDependence):
53+
54+
```@repl traits
55+
Traits.Fixed <: Traits.VariableDependence
56+
Traits.NonFixed <: Traits.VariableDependence
57+
```
58+
59+
### Mutability
60+
61+
Does a function allocate a new output, or write into a pre-allocated buffer?
62+
63+
| Type | Meaning |
64+
|---|---|
65+
| [`Traits.OutOfPlace`](@ref CTBase.Traits.OutOfPlace) | returns a new value |
66+
| [`Traits.InPlace`](@ref CTBase.Traits.InPlace) | writes into a buffer (first arg) |
67+
68+
### Other families
69+
70+
These traits encode properties that are fixed at construction time and carried
71+
as type parameters. They are not opted into via the two-method contract described
72+
below — they are passed directly as type arguments.
73+
74+
| Family | Values |
75+
|---|---|
76+
| Integration mode | [`Traits.EndPointMode`](@ref CTBase.Traits.EndPointMode), [`Traits.TrajectoryMode`](@ref CTBase.Traits.TrajectoryMode) |
77+
| Dynamics | [`Traits.StateDynamics`](@ref CTBase.Traits.StateDynamics), [`Traits.HamiltonianDynamics`](@ref CTBase.Traits.HamiltonianDynamics), [`Traits.AugmentedHamiltonianDynamics`](@ref CTBase.Traits.AugmentedHamiltonianDynamics) |
78+
| Automatic differentiation | [`Traits.WithAD`](@ref CTBase.Traits.WithAD), [`Traits.WithoutAD`](@ref CTBase.Traits.WithoutAD) |
79+
| Variable costate | [`Traits.SupportsVariableCostate`](@ref CTBase.Traits.SupportsVariableCostate), [`Traits.NoVariableCostate`](@ref CTBase.Traits.NoVariableCostate) |
80+
81+
## The trait contract
82+
83+
A type opts in to a trait by implementing **two methods**: one declaring that it
84+
*has* the trait, and one returning the trait *value*. The boolean predicates
85+
([`Traits.is_autonomous`](@ref CTBase.Traits.is_autonomous),
86+
[`Traits.is_variable`](@ref CTBase.Traits.is_variable), …) then follow
87+
generically — they are not implemented per type.
88+
89+
For time and variable dependence:
90+
91+
```@repl traits
92+
struct MyObject end
93+
94+
Traits.has_time_dependence_trait(::MyObject) = true
95+
Traits.time_dependence(::MyObject) = Traits.NonAutonomous
96+
97+
Traits.has_variable_dependence_trait(::MyObject) = true
98+
Traits.variable_dependence(::MyObject) = Traits.Fixed
99+
100+
obj = MyObject()
101+
Traits.is_autonomous(obj)
102+
Traits.is_nonautonomous(obj)
103+
Traits.is_variable(obj)
104+
Traits.is_nonvariable(obj)
105+
```
106+
107+
For mutability, the same pattern applies with `has_mutability_trait` and `mutability`:
108+
109+
```@repl traits
110+
struct MyMutableObject end
111+
112+
Traits.has_mutability_trait(::MyMutableObject) = true
113+
Traits.mutability(::MyMutableObject) = Traits.InPlace
114+
115+
Traits.is_inplace(MyMutableObject())
116+
Traits.is_outofplace(MyMutableObject())
117+
```
118+
119+
If a type does not declare a trait, the predicates throw an informative error
120+
rather than returning a wrong default:
121+
122+
```@repl traits
123+
try # hide
124+
Traits.is_autonomous(3.14)
125+
catch e # hide
126+
showerror(IOContext(stdout, :color => false), e) # hide
127+
end # hide
128+
```
129+
130+
!!! note "Trait types are shared"
131+
Because trait types (e.g. `Traits.Autonomous`) are defined in a single place,
132+
a type that carries `Traits.Autonomous` as a type parameter and an object that
133+
implements `time_dependence` returning `Traits.Autonomous` are compatible by
134+
construction — no conversion or mapping needed.
135+
136+
## Accessor / predicate summary
137+
138+
| Trait value function | Boolean predicates |
139+
|---|---|
140+
| [`Traits.time_dependence`](@ref CTBase.Traits.time_dependence) | `is_autonomous`, `is_nonautonomous` |
141+
| [`Traits.variable_dependence`](@ref CTBase.Traits.variable_dependence) | `is_variable`, `is_nonvariable`, `has_variable` |
142+
| [`Traits.mutability`](@ref CTBase.Traits.mutability) | `is_inplace`, `is_outofplace` |
143+
| [`Traits.ad_trait`](@ref CTBase.Traits.ad_trait) ||
144+
| [`Traits.variable_costate_trait`](@ref CTBase.Traits.variable_costate_trait) ||
145+
| [`Traits.dynamics_trait`](@ref CTBase.Traits.dynamics_trait) ||
146+
147+
## See Also
148+
149+
- [Exceptions guide](exceptions.md) — understanding `IncorrectArgument` and `NotImplemented`.

docs/src/index.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ It provides the **base layer** shared by all packages: common types, structured
2727
| [`CTBase.Core`](@ref) | Fundamental numeric type alias (`ctNumber`) and internal display helpers |
2828
| [`CTBase.Descriptions`](@ref) | Symbolic description tuples: catalogue management, pattern completion, similarity search |
2929
| [`CTBase.Exceptions`](@ref) | Typed exception hierarchy with rich context fields |
30+
| [`CTBase.Traits`](@ref) | Compile-time trait types for time dependence, variable dependence, mutability, and dynamics dispatch |
3031
| [`CTBase.DevTools`](@ref) | Developer tools with tag-based dispatch for `run_tests`, `postprocess_coverage`, and `automatic_reference_documentation` |
3132
| [`CTBase.Unicode`](@ref) | Unicode subscript/superscript helpers for display |
3233

@@ -35,6 +36,7 @@ It provides the **base layer** shared by all packages: common types, structured
3536
- **[Getting Started](getting-started.md)** — installation, mental model, 5-minute walkthrough.
3637
- **[Descriptions](guide/descriptions.md)** — catalogue API, pattern matching, error handling.
3738
- **[Exceptions](guide/exceptions.md)** — exception hierarchy, choosing the right type, best practices.
39+
- **[Traits](guide/traits.md)** — compile-time trait types, the opt-in contract, and predicate functions.
3840
- **[Test Runner](guide/test-runner.md)** — modular test infrastructure with `CTBase.DevTools.run_tests`.
3941
- **[Coverage](guide/coverage.md)** — post-processing coverage artifacts with `CTBase.postprocess_coverage`.
4042
- **[API Documentation](guide/api-documentation.md)** — auto-generating per-module API pages.

src/CTBase.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ using .Strategies
3232
include(joinpath(@__DIR__, "Orchestration", "Orchestration.jl"))
3333
using .Orchestration
3434

35+
# Traits module - trait types and trait-based dispatch (moved from CTFlows)
36+
include(joinpath(@__DIR__, "Traits", "Traits.jl"))
37+
using .Traits
38+
3539
# Unicode module - Unicode character utilities
3640
include(joinpath(@__DIR__, "Unicode", "Unicode.jl"))
3741
using .Unicode

src/Strategies/api/describe_registry.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,7 @@ julia> _strategy_type_name(Collocation)
395395
- This is the most common case, handling concrete instantiated types
396396
- For parameterized types, each parameter is formatted recursively
397397
398-
See also: [`describe`](@ref), [`_describe_parameter_registry`](@ref)
398+
See also: [`CTBase.Strategies.describe`](@ref), [`CTBase.Strategies._describe_parameter_registry`](@ref)
399399
"""
400400
function _strategy_type_name(T::DataType)
401401
base_name = string(T.name.name)
@@ -427,7 +427,7 @@ the type parameter variable name.
427427
- This is a fallback for generic types that are not yet instantiated
428428
- Less common than the DataType method in typical usage
429429
430-
See also: [`_strategy_type_name(::DataType)`](@ref)
430+
See also: [`CTBase.Strategies._strategy_type_name(::DataType)`](@ref)
431431
"""
432432
function _strategy_type_name(T::UnionAll)
433433
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
452452
- This is the ultimate fallback for edge cases
453453
- Simply converts the type to a string representation
454454
455-
See also: [`_strategy_type_name(::DataType)`](@ref), [`_strategy_type_name(::UnionAll)`](@ref)
455+
See also: [`CTBase.Strategies._strategy_type_name(::DataType)`](@ref), [`CTBase.Strategies._strategy_type_name(::UnionAll)`](@ref)
456456
"""
457457
function _strategy_type_name(T::Type)
458458
return string(T)
@@ -488,7 +488,7 @@ julia> _strategy_base_name(Collocation)
488488
- Used specifically for strategy headers to avoid redundancy with parameter display
489489
- Handles both DataType and UnionAll types
490490
491-
See also: [`_strategy_type_name`](@ref), [`describe`](@ref)
491+
See also: [`CTBase.Strategies._strategy_type_name`](@ref), [`CTBase.Strategies.describe`](@ref)
492492
"""
493493
function _strategy_base_name(T::DataType)
494494
return string(T.name.name)

0 commit comments

Comments
 (0)