diff --git a/README.md b/README.md index dad0b86..c3069c2 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # 🦖DynOptInterface -[![Stable](https://img.shields.io/badge/docs-stable-blue.svg)](https://JuDO-dev.github.io/DynOptInterface.jl/stable/) + [![Dev](https://img.shields.io/badge/docs-dev-blue.svg)](https://JuDO-dev.github.io/DynOptInterface.jl/dev/) [![Build Status](https://github.com/JuDO-dev/DynOptInterface.jl/actions/workflows/CI.yml/badge.svg?branch=dev)](https://github.com/JuDO-dev/DynOptInterface.jl/actions/workflows/CI.yml?query=branch%3Adev) -[![Coverage](https://codecov.io/gh/JuDO-dev/DynOptInterface.jl/branch/dev/graph/badge.svg)](https://codecov.io/gh/JuDO-dev/DynOptInterface.jl) + diff --git a/docs/make.jl b/docs/make.jl index df7687e..0406ba2 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -1,8 +1,8 @@ -using DynOptInterface +import DynOptInterface using Documenter using DocumenterInterLinks -DocMeta.setdocmeta!(DynOptInterface, :DocTestSetup, :(using DynOptInterface); recursive=true) +DocMeta.setdocmeta!(DynOptInterface, :DocTestSetup, :(import DynOptInterface as DOI); recursive=true) const _PAGES = [ "Home" => "index.md", diff --git a/docs/src/reference/abstractions.md b/docs/src/reference/abstractions.md index 63055cf..a67f2dd 100644 --- a/docs/src/reference/abstractions.md +++ b/docs/src/reference/abstractions.md @@ -4,26 +4,18 @@ CurrentModule = DynOptInterface # Abstractions -The following are sub-types of [`AbstractDynamicFunction`](@ref): - -* [`AbstractAlgebraicFunction`](@ref) - * ``t_i`` [`DomainIndex`](@ref) - * ``t_i \mapsto y_j(t_i)`` [`DynamicVariableIndex`](@ref) - * ``t_i \mapsto a(y(t_i), t_i, x)`` [`NonlinearAlgebraicFunction`](@ref) -* [`AbstractDifferentialFunction`](@ref) - * ``t_i \mapsto \dot{y}_j(t_i)`` [`DynamicVariableDerivative`](@ref) - * ``t_i \mapsto \dot{y}_j(t_i) - a(y(t_i), t_i, x)`` [`ExplicitDifferentialFunction`](@ref) - * ``t_i \mapsto r(\dot{y}(t_i), y(t_i), t_i, x)`` [`NonlinearDifferentialFunction`](@ref) -* [`AbstractBoundaryFunction`](@ref) - * ``a(y(t_i^0), t_i^0, x)`` [`Initial`](@ref) - * ``a(y(t_i^f), t_i^f, x)`` [`Final`](@ref) - * ``b(y(t^0), y(t^f), t^0, t^f, x)`` [`NonlinearBoundaryFunction`](@ref) -* ``\int_{t_i^0}^{t_i^f} a(y(t_i), t_i, x) \mathrm{d}t_i`` [`IntegralFunction`](@ref) -* ``b(y(t_i^0), y(t_i^f), t_i^0, t_i^f, x) + \int_{t_i^0}^{t_i^f} a(y(t_i), t_i, x) \mathrm{d}t_i`` [`BolzaFunction`](@ref) +## Functions ```@docs AbstractDynamicFunction AbstractAlgebraicFunction AbstractDifferentialFunction AbstractBoundaryFunction +``` + +## Attributes + +```@docs +AbstractDomainAttribute +AbstractDynamicVariableAttribute ``` \ No newline at end of file diff --git a/docs/src/reference/algebraic_functions.md b/docs/src/reference/algebraic_functions.md index b517c49..c86f739 100644 --- a/docs/src/reference/algebraic_functions.md +++ b/docs/src/reference/algebraic_functions.md @@ -4,6 +4,12 @@ CurrentModule = DynOptInterface # Algebraic Functions +## Types + ```@docs +LinearAlgebraicTerm +LinearAlgebraicFunction +SquaredAlgebraicTerm +SquaredAlgebraicFunction NonlinearAlgebraicFunction ``` \ No newline at end of file diff --git a/docs/src/reference/domains.md b/docs/src/reference/domains.md index 9057d60..f57c877 100644 --- a/docs/src/reference/domains.md +++ b/docs/src/reference/domains.md @@ -4,10 +4,30 @@ CurrentModule = DynOptInterface # Domains +## Type + ```@docs DomainIndex +``` + +## Attributes +```@docs +DomainName +DomainInitialPrimalStart +DomainFinalPrimalStart +DomainInitialPrimal +DomainFinalPrimal +``` + +## Functions + +```@docs supports_domain +add_domain +``` + +## Errors +```@docs UnsupportedDomain AddDomainNotAllowed -add_domain ``` \ No newline at end of file diff --git a/docs/src/reference/dynamic_variables.md b/docs/src/reference/dynamic_variables.md index 4d84bd5..f47916a 100644 --- a/docs/src/reference/dynamic_variables.md +++ b/docs/src/reference/dynamic_variables.md @@ -4,10 +4,29 @@ CurrentModule = DynOptInterface # Dynamic Variables +## Type + ```@docs DynamicVariableIndex +``` + +## Attributes +```@docs +DynamicVariableName +DynamicVariablePrimalStart +DynamicVariablePrimal +``` + +## Functions + +```@docs supports_dynamic_variable +add_dynamic_variable +``` + +## Errors + +```@docs UnsupportedDynamicVariable AddDynamicVariableNotAllowed -add_dynamic_variable ``` \ No newline at end of file diff --git a/src/abstractions.jl b/src/abstractions.jl index 6b8c5e7..87ed371 100644 --- a/src/abstractions.jl +++ b/src/abstractions.jl @@ -8,20 +8,53 @@ abstract type AbstractDynamicFunction <: MOI.AbstractScalarFunction end """ AbstractAlgebraicFunction <: AbstractDynamicFunction -Abstract supertype for algebraic functions. +Abstract supertype for algebraic functions. That is, expressions that may contain +``y(t)`` or ``t``, but not ``\\dot{y}(t)``. """ abstract type AbstractAlgebraicFunction <: AbstractDynamicFunction end """ AbstractDifferentialFunction <: AbstractDynamicFunction -Abstract supertype for differential functions. +Abstract supertype for differential functions. That is, expressions that may contain +``\\dot{y}(t)``, ``y(t)``, or ``t``. """ abstract type AbstractDifferentialFunction <: AbstractDynamicFunction end """ AbstractBoundaryFunction <: AbstractDynamicFunction -Abstract supertype for dynamic functions evaluated at the domain boundaries. +Abstract supertype for functions evaluated at domain boundaries. That is, +expressions that may contain ``y(t^0)``, ``y(t^f)``, ``t^0``, or ``t^f``. """ -abstract type AbstractBoundaryFunction <: AbstractDynamicFunction end \ No newline at end of file +abstract type AbstractBoundaryFunction <: AbstractDynamicFunction end + +""" + AbstractDomainAttribute + +Abstract supertype for attribute objects that can be used to set or get attributes +(properties) of domains in the model. +""" +abstract type AbstractDomainAttribute end + +""" + AbstractDynamicVariableAttribute + +Abstract supertype for attributs objects that can be used to set or get attributes +(properties) of dynamic variables in the model. +""" +abstract type AbstractDynamicVariableAttribute end + +const AnyDynamicAttribute = Union{ + AbstractDomainAttribute, + AbstractDynamicVariableAttribute, +} + +function MOI.get(model::MOI.ModelLike, attr::AnyDynamicAttribute, args...) + return throw( + MOI.GetAttributeNotAllowed( + attr, + "$(typeof(model)) does not support getting the attribute $(attr).", + ) + ) +end \ No newline at end of file diff --git a/src/algebraic_functions.jl b/src/algebraic_functions.jl index 85f5234..d7faf8b 100644 --- a/src/algebraic_functions.jl +++ b/src/algebraic_functions.jl @@ -1,8 +1,57 @@ +## Types + +""" + LinearAlgebraicTerm{T} + +```math +t_i \\mapsto c_j y_j(t_i) +``` +""" +struct LinearAlgebraicTerm{T} + coefficient::T + y_j::DynamicVariableIndex +end + +""" + LinearAlgebraicFunction{T} <: AbstractAlgebraicFunction + +```math +t_i \\mapsto c^\\top y(t_i) +``` +""" +struct LinearAlgebraicFunction{T} <: AbstractAlgebraicFunction + terms::Vector{LinearAlgebraicTerm{T}} +end + +""" + SquaredAlgebraicTerm{T} + +```math +t_i \\mapsto y_j(t_i) c_{jk} y_k(t_i) +``` +""" +struct SquaredAlgebraicTerm{T} + coefficient::T + y_j::DynamicVariableIndex + y_k::DynamicVariableIndex +end + +""" + SquaredAlgebraicFunction{T} + +```math +t_i \\mapsto y(t_i)^\\top C y(t_i) +``` +""" +struct SquaredAlgebraicFunction{T} + terms::Vector{SquaredAlgebraicTerm{T}} +end + """ NonlinearAlgebraicFunction <: AbstractAlgebraicFunction ```math -t_i \\mapsto a(y(t_i), t_i, x) +t_i \\mapsto f_a(y(t_i), t_i, x) ``` Similar to [`MathOptInterface.ScalarNonlinearFunction`](@ref), diff --git a/src/boundary_functions.jl b/src/boundary_functions.jl index 19a324b..3afda1f 100644 --- a/src/boundary_functions.jl +++ b/src/boundary_functions.jl @@ -61,7 +61,7 @@ const _NONLINEAR_BOUNDARY_TYPES = Union{ NonlinearBoundaryFunction <: AbstractBoundaryFunction ```math -b(y(t^0), y(t^f), t^0, t^f, x) +f_b(y(t^0), y(t^f), t^0, t^f, x) ``` Similar to [`MathOptInterface.ScalarNonlinearFunction`](@extref), diff --git a/src/differential_functions.jl b/src/differential_functions.jl index d088932..a83a8fa 100644 --- a/src/differential_functions.jl +++ b/src/differential_functions.jl @@ -43,7 +43,7 @@ end NonlinearDifferentialFunction <: AbstractDifferentialFunction ```math -t_i \\mapsto r(\\dot{y}(t_i), y(t_i), t_i, x) +t_i \\mapsto f_d(\\dot{y}(t_i), y(t_i), t_i, x) ``` Similar to `MOI.ScalarNonlinearFunction`, diff --git a/src/domains.jl b/src/domains.jl index 35e2057..e573b67 100644 --- a/src/domains.jl +++ b/src/domains.jl @@ -1,8 +1,10 @@ +## Type + """ DomainIndex <: AbstractAlgebraicFunction ```math -t_i +t_i \\in [t_i^0, t_i^f] ``` A type-safe wrapper for `Int64` for use in referencing domains. """ @@ -16,6 +18,57 @@ function MOI.Utilities._to_string(::MOI.Utilities._PrintOptions, ::MOI.ModelLike return string("t[", t_i.value, "]") end +## Attributes + +""" + DomainName <: AbstractDomainAttribute + +A domain attribute for a `String` identifying a [`DomainIndex`](@ref). +If not set, it has a default value of `""`. +""" +struct DomainName <: AbstractDomainAttribute end + +MOI.attribute_value_type(::DomainName) = String + +""" + DomainInitialPrimalStart <: AbstractDomainAttribute + +A domain attribute for setting a starting value for ``t_i^0``, which may +help warm-start the optimizer. It is either a number or a `nothing` (unset). +""" +struct DomainInitialPrimalStart <: AbstractDomainAttribute end + +""" + DomainFinalPrimalStart <: AbstractDomainAttribute + +A domain attribute for setting a starting value for ``t_i^f``, which may +help warm-start the optimizer. It is either a number or a `nothing` (unset). +""" +struct DomainFinalPrimalStart <: AbstractDomainAttribute end + +""" + DomainInitialPrimal <: AbstractDomainAttribute + +A domain attribute for setting or getting ``t_i^0``. It should have the +same behaviour as the [`MathOptInterface.VariablePrimal`](@extref) attribute. +""" +struct DomainInitialPrimal <: AbstractDomainAttribute + result_index::Int + DomainInitialPrimal(result_index::Int=1) = new(result_index) +end + +""" + DomainFinalPrimal <: AbstractDomainAttribute + +A domain attribute for setting or getting ``t_i^f``. It should have the +same behaviour as the [`MathOptInterface.VariablePrimal`](@extref) attribute. +""" +struct DomainFinalPrimal <: AbstractDomainAttribute + result_index::Int + DomainFinalPrimal(result_index::Int=1) = new(result_index) +end + +## Functions and Errors """ supports_domain(model::MOI.ModelLike) diff --git a/src/dynamic_variables.jl b/src/dynamic_variables.jl index 1665e41..459b10a 100644 --- a/src/dynamic_variables.jl +++ b/src/dynamic_variables.jl @@ -1,3 +1,5 @@ +## Type + """ DynamicVariableIndex <: AbstractDynamicFunction @@ -17,6 +19,41 @@ function MOI.Utilities._to_string(::MOI.Utilities._PrintOptions, ::MOI.ModelLike return string("y[", y_j.value, "]") end +## Attributes + +""" + DynamicVariableName <: AbstractDomainAttribute + +A dynamic variable attribute for a `String` identifying a +[`DynamicVariableIndex`](@ref). If not set, it has a default value of `""`. +""" +struct DynamicVariableName <: AbstractDynamicVariableAttribute end + +MOI.attribute_value_type(::DynamicVariableName) = String + +""" + DynamicVariablePrimalStart <: AbstractDynamicVariableAttribute + +A dynamic variable attribute for setting a starting function for ``y_j(t_i)``, +which may help warm-start the optimizer. It is either a `nothing` (unset) +or a single-argument function of `T<:Real`. +""" +struct DynamicVariablePrimalStart <: AbstractDynamicVariableAttribute end + +""" + DynamicVariablePrimal <: AbstractDynamicVariableAttribute + +A dynamic variable attribute for setting or getting ``y_j(t_i)``. It should +be a single-argument function of `T<:Real`. It should have the same behaviour +as the [`MathOptInterface.VariablePrimal`](@extref) attribute. +""" +struct DynamicVariablePrimal <: AbstractDynamicVariableAttribute + result_index::Int + DynamicVariablePrimal(result_index::Int=1) = new(result_index) +end + +## Functions and Errors + """ supports_dynamic_variable(model::MOI.ModelLike) diff --git a/test/algebraic_functions.jl b/test/algebraic_functions.jl new file mode 100644 index 0000000..c29653c --- /dev/null +++ b/test/algebraic_functions.jl @@ -0,0 +1,24 @@ +@testset "NonlinearAlgebraicFunction" begin + + t = DOI.DomainIndex(1) + + @test_nowarn DOI.NonlinearAlgebraicFunction(:call, [2.0], t) + @test_throws ErrorException DOI.NonlinearAlgebraicFunction(:call, [1+2im], t) + + x = MOI.VariableIndex(1) + @test_nowarn DOI.NonlinearAlgebraicFunction(:call, [x], t) + + t_2 = DOI.DomainIndex(2) + @test_nowarn DOI.NonlinearAlgebraicFunction(:call, [t], t) + @test_throws ErrorException DOI.NonlinearAlgebraicFunction(:+, [t, t_2], t) + + y = DOI.DynamicVariableIndex(1, t) + y_2 = DOI.DynamicVariableIndex(2, t_2) + @test_nowarn DOI.NonlinearAlgebraicFunction(:call, [y], t) + @test_throws ErrorException DOI.NonlinearAlgebraicFunction(:call, [y_2], t) + + a = DOI.NonlinearAlgebraicFunction(:call, [y], t) + @test_nowarn DOI.NonlinearAlgebraicFunction(:call, [a], t) + @test_throws ErrorException DOI.NonlinearAlgebraicFunction(:call, [a], t_2) + +end \ No newline at end of file diff --git a/test/differential_functions.jl b/test/differential_functions.jl new file mode 100644 index 0000000..e69de29 diff --git a/test/domains.jl b/test/domains.jl new file mode 100644 index 0000000..12ebc49 --- /dev/null +++ b/test/domains.jl @@ -0,0 +1,22 @@ +@testset "DomainIndex" begin + + t_1 = DOI.DomainIndex(1) + @test isbits(t_1) + +end + +@testset "supports_domain" begin + + struct DummyModel <: MOI.ModelLike end + model = DummyModel() + @test DOI.supports_domain(model) == false + +end + +@testset "add_domain" begin + + struct DummyModel <: MOI.ModelLike end + model = DummyModel() + @test_throws DOI.AddDomainNotAllowed DOI.add_domain(model) + +end \ No newline at end of file diff --git a/test/dynamic_variables.jl b/test/dynamic_variables.jl new file mode 100644 index 0000000..b84417c --- /dev/null +++ b/test/dynamic_variables.jl @@ -0,0 +1,23 @@ +@testset "DynamicVariableIndex" begin + + t_1 = DOI.DomainIndex(1) + y_1 = DOI.DynamicVariableIndex(1, t_1) + @test isbits(y_1) + +end + +@testset "supports_dynamic_variable" begin + + struct DummyModel <: MOI.ModelLike end + model = DummyModel() + @test DOI.supports_dynamic_variable(model) == false + +end + +@testset "add_dynamic_variable" begin + + struct DummyModel <: MOI.ModelLike end + model = DummyModel() + @test_throws DOI.AddDynamicVariableNotAllowed DOI.add_dynamic_variable(model) + +end \ No newline at end of file diff --git a/test/runtests.jl b/test/runtests.jl index 942a0cc..bd61cf9 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,6 +1,8 @@ -using DynOptInterface +import DynOptInterface as DOI +import MathOptInterface as MOI using Test -@testset "DynOptInterface.jl" begin - # Write your tests here. -end \ No newline at end of file +include("domains.jl") +include("dynamic_variables.jl") +include("algebraic_functions.jl") +include("differential_functions.jl") \ No newline at end of file