Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

232 preparing for inplace nlp #271

Merged
merged 37 commits into from
Sep 9, 2024
Merged

Conversation

jbcaillau
Copy link
Member

No description provided.

@jbcaillau jbcaillau linked an issue Aug 29, 2024 that may be closed by this pull request
Copy link

github-actions bot commented Aug 29, 2024

Package name latest stable
CTDirect.jl compat: v0.13.1 compat: v0.13.1
CTFlows.jl compat: v0.13.1 compat: v0.13.1
OptimalControl.jl compat: v0.13.1 compat: v0.13.1

j = 1
for i ∈ 1:length(ψf)
li = ψs[i]
ψf[i](val[j:(j + li - 1)], t, x, u, v)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thing that val[j:(j + li - 1)] will allocate a new vector.
You probably need view(val, j:(j + li - 1)).

Copy link
Member Author

@jbcaillau jbcaillau Sep 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@amontoison this is subtle... any doc / reference on this? Apart from
https://docs.julialang.org/en/v1/manual/performance-tips/#tools

Copy link
Member Author

@jbcaillau jbcaillau Sep 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@amontoison thanks, as it is even worse than I thought (check g1 😬):

julia> f!(x) = begin x[1] = 7.; x[2] = 8. end
f! (generic function with 2 methods)

julia> g1() = begin
       x = zeros(Float64, 10)
       for i  1:1000 f!(x[3:4]) end
       println("x =", x)
       end
g1 (generic function with 1 method)

julia> g2() = begin
       x = zeros(Float64, 10)
       f!(view(x, 3:4))
       println("x =", x)
       end
g2 (generic function with 1 method)

julia> g3() = begin
       x = zeros(Float64, 10)
       for i  1:1000 f!(view(x, 3:4)) end
       println("x =", x)
       end
g3 (generic function with 1 method)

julia> @allocated g1()
x =[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
85728

julia> @allocated g2()
x =[0.0, 0.0, 7.0, 8.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
5728

julia> @allocated g3()
x =[0.0, 0.0, 7.0, 8.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
6032

julia> @allocated g3()
x =[0.0, 0.0, 7.0, 8.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
5728

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NB. The syntax with @view is supposed to generate the same code (and allows begin / end indexing):

julia> g4() = begin
       x = zeros(Float64, 10)
       for i  1:1000 f!(@view x[3:4]) end
       println("x =", x)
       end
g4 (generic function with 1 method)

julia> @allocated g4()
x =[0.0, 0.0, 7.0, 8.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
5728

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

@jbcaillau jbcaillau Sep 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So even in this case, cases 1 and 2 below make a copy y[3:4]?

julia> let 
       x = zeros(4)
       y = ones(4)
       println(@allocated x[1:2] = y[3:4])
       x
       end
80
4-element Vector{Float64}:
 1.0
 1.0
 0.0
 0.0

julia> let 
       x = zeros(4)
       y = ones(4)
       println(@allocated x[1:2] .= y[3:4])
       x
       end
80
4-element Vector{Float64}:
 1.0
 1.0
 0.0
 0.0

julia> let 
       x = zeros(4)
       y = ones(4)
       println(@allocated x[1:2] = @view y[3:4])
       x
       end
0
4-element Vector{Float64}:
 1.0
 1.0
 0.0
 0.0

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, they do a copy in both cases

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@PierreMartinon check above: slices in the rhs of an affectation x[...] = y[...] are copied unless a view is used, x[...] = view(y, ...)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I know... Julia compiler right now is not great at optimizations. See also: https://discourse.julialang.org/t/common-allocation-mistakes/66127

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@amontoison
Copy link
Contributor

@jbcaillau For in-place code, I suggest adding unit tests with @allocated.
It's so easy to miss some allocations...
I recommend this kind of test: https://github.com/JuliaSmoothOptimizers/Krylov.jl/blob/main/test/test_allocations.jl#L37-L51
It guarantees that your code is in-place and that you won't introduce extra allocations in the future with new modifications.

@jbcaillau
Copy link
Member Author

@ocots more or less trivial changes to types / functions to include in_place definitions (constraints, dynamics, cost). everything kept for out_of_place to be still OK (ongoing test). please review the diff and tell me what you think.

p) ? ... in constraint\!
Comment on lines +60 to +62
struct BoundaryConstraint!{variable_dependence}
f!::Function
end
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jbcaillau f!::Function will not be efficient because Function is a generic type.
You need a parametric structure like this:

struct BoundaryConstraint!{F}
    f!::F
end

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jbcaillau f!::Function will not be efficient because Function is a generic type. You need a parametric structure like this:

struct BoundaryConstraint!{F}
    f!::F
end

@amontoison Instead of

struct CallableType
    f::Function
end

(F::CallableType)(n::Int) = F.f(n)

F = CallableType(n->2n)

Do you recommend this?

struct CallableType{T}
    f::T
end

(F::CallableType)(n::Int) = F.f(n)

f = n->2n
F = CallableType{typeof(f)}(f)

Copy link
Contributor

@amontoison amontoison Sep 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, and you can avoid to specify typeof(f), Julia will do that automatically for you:

struct CallableType{T}
    f::T
end

(F::CallableType)(n::Int) = F.f(n)

f = n->2n
F = CallableType(f)

By having a parametric structure CallableType, Julia doesn't need to re-infer the type of F.f at every call. After the first call, a compiled version is available, and future calls to CallableType are faster.
f::Function just restricts f to be a function but doesn't help the internal compiler.

Copy link
Member

@ocots ocots Sep 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And if we have to types. How does it work?

struct CallableType{T, U}
    f::T
end

f = n->2n
F = CallableType{SomeType}(f)

Is this better?

struct CallableType{T <: Function}
    f::T
end

Copy link
Contributor

@amontoison amontoison Sep 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the goal of U? It is for dispatch like a symbol :inplace :not_inplace?
If you don't have any attribute of type U, it should not be used in practice.
The second structure is the best one

struct CallableType{T <: Function}
    f::T
end

But I'm wondering if what you want is not just a "functor": https://docs.julialang.org/en/v1/manual/methods/#Function-like-objects

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You want to keep variable_dependence as the first parametric type because you do the dispatch on it and not the other one.

So dispatch processes the arguments starting from the first until it can determine a match ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, and if you are not doing anything special for the last arguments, you can avoid parametrizing your functions with all arguments and only parametrize with the first one. This will avoid compiling a method for each combination if it's not needed. I think it's explained somewhere in Julia's documentation (over-parametrization).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@amontoison a simple example/illustration somewhere?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Catching up on this today, this is exactly what we discussed yesterday @ocots

@jbcaillau
Copy link
Member Author

jbcaillau commented Sep 5, 2024

@ocots more or less trivial changes to types / functions to include in_place definitions (constraints, dynamics, cost). everything kept for out_of_place to be still OK (ongoing test). please review the diff and tell me what you think.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ocots 👍🏽 missed that one

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ocots well done! definitions in the wrong @match branch. actually I wanted them to be a the very beginning (before @match). moving them.

@jbcaillau
Copy link
Member Author

jbcaillau commented Sep 5, 2024

@amontoison another question about treating as uniformly as possible vectors and scalars, related to #271 (comment): up to now we use .= to treat uniformly (length one) vectors and scalar, like in

julia> x = [0.]
1-element Vector{Float64}:
 0.0

julia> y = [1.]
1-element Vector{Float64}:
 1.0

julia> z = 2.
2.0

julia> x[:] .= y[1]
1-element view(::Vector{Float64}, :) with eltype Float64:
 1.0

julia> x[:] .= z[1]
1-element view(::Vector{Float64}, :) with eltype Float64:
 2.0

Introducing views to avoid copying the rhs is still OK with vectors, not with scalars:

julia> x[:] .= view(y, 1)
1-element view(::Vector{Float64}, :) with eltype Float64:
 1.0

julia> x[:] .= view(z, 1)
ERROR: MethodError: no method matching view(::Float64, ::Int64)

Of course, we can do sth like

julia> __view(x, rg) = (rg isa Integer) ? x[rg] : view(x, rg)
__view (generic function with 1 method)

julia> x[:] .= __view(y, 1)
1-element view(::Vector{Float64}, :) with eltype Float64:
 1.0

julia> x[:] .= __view(z, 1)
1-element view(::Vector{Float64}, :) with eltype Float64:
 2.0

but is it the best way?

@amontoison
Copy link
Contributor

amontoison commented Sep 5, 2024

@jbcaillau
I will probably use multiple dispatch so that the compiler knows the output type for each combination:

__view(x::Number, rg) = x 
__view(x::AbstractVector, rg::Integer) = x[rg]
__view(x::AbstractVector, rg::UnitRange) = view(x, rg)

But it's quite cheap to use an array of length 1 instead of a scalar rhs, so it could be more efficient to use a vector in all-cases such that the compiler can infer the type of each parameter and variable.

Instead of view, you could also use the 5-arguments version of copyto!:

A = zeros(10)
B = [i for i = 1:10]
start_A = 5
start_B = 3
N = 4
copyto!(A, start_A, B, start_B, N)
10-element Vector{Float64}:
 0.0
 0.0
 0.0
 0.0
 3.0
 4.0
 5.0
 6.0
 0.0
 0.0

@amontoison
Copy link
Contributor

@ocots @jbcaillau Before that I forgot, you are using quite often a foo::Union{Nothing, ...} inside your structures for the type of the attributes. The compiler doesn't like that and it leads to additional allocations because it needs to check at runtime that it's a Nothing or not.
You can change that for foo::T and at the top of your structure T <: Union{Nothing, ...}.

@amontoison
Copy link
Contributor

amontoison commented Sep 5, 2024

For all these kinds of stuff I used JET in the past and kept an example here.

using CTBase, JET
report_package(CTBase)
═════ 93 possible errors found ═════
┌ getFullDescription(desc::Tuple{Vararg{Symbol}}, desc_list::Tuple{Vararg{Tuple{Vararg{Symbol}}}}) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/description.jl:117
│┌ intersect(itr::Tuple{Vararg{Symbol}}, itrs::Tuple{Vararg{Symbol}}) @ Base ./array.jl:2859
││┌ _shrink(shrinker!::typeof(intersect!), itr::Tuple{Vararg{Symbol}}, itrs::Tuple{Tuple{Vararg{Symbol}}}) @ Base ./array.jl:2855
│││┌ intersect!(s::Set, itr::Tuple{Vararg{Symbol}}) @ Base ./abstractset.jl:197
││││┌ union!(s::Set{Union{}}, itr::Tuple{Vararg{Symbol}}) @ Base ./abstractset.jl:104
│││││┌ sizehint!(s::Set{Union{}}, newsz::Int64) @ Base ./set.jl:120
││││││┌ sizehint!(d::Dict{Union{}, Nothing}, newsz::Int64) @ Base ./dict.jl:225
│││││││┌ rehash!(h::Dict{Union{}, Nothing}, newsz::Int64) @ Base ./dict.jl:192
││││││││┌ getindex(A::Vector{Union{}}, i1::Int64) @ Base ./essentials.jl:13
│││││││││ invalid builtin function call: Base.arrayref($(Expr(:boundscheck)), A::Vector{Union{}}, i1::Int64)
││││││││└────────────────────
┌ CTBase.BoundaryConstraint(f::Function, dependencies::Vararg{DataType}) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/functions.jl:34
│┌ __check_dependencies(dependencies::Tuple{Vararg{DataType}}) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_model-type.jl:230
││┌ filter(f::CTBase.var"#35#38", t::Tuple{Vararg{DataType}}) @ Base ./tuple.jl:464
│││┌ filter(f::CTBase.var"#35#38", a::Vector{Union{}}) @ Base ./array.jl:2673
││││┌ iterate(A::Vector{Union{}}) @ Base ./array.jl:945
│││││┌ iterate(A::Vector{Union{}}, i::Int64) @ Base ./array.jl:945
││││││┌ getindex(A::Vector{Union{}}, i1::Int64) @ Base ./essentials.jl:13
│││││││ invalid builtin function call: Base.arrayref($(Expr(:boundscheck)), A::Vector{Union{}}, i1::Int64)
││││││└────────────────────
┌ ctupperscript(i::Integer) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/utils.jl:51
│ no matching method found `convert(::Type{Char}, ::Nothing)`: convert(CTBase.Char, _8::Nothing)
└────────────────────
┌ __ctjacobian(f::Function, x::Real) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/utils.jl:121
│┌ jacobian(f::CTBase.var"#28#29"{<:Function}, x::Vector{T} where T<:Real) @ ForwardDiff /home/alexis/.julia/packages/ForwardDiff/PcZ48/src/jacobian.jl:19
││┌ jacobian(f::CTBase.var"#28#29"{}, x::Vector{…} where T<:Real, cfg::ForwardDiff.JacobianConfig{…} where {}) @ ForwardDiff /home/alexis/.julia/packages/ForwardDiff/PcZ48/src/jacobian.jl:19
│││┌ jacobian(f::CTBase.var"#28#29"{}, x::Vector{…} where T<:Real, cfg::ForwardDiff.JacobianConfig{…} where {}, ::Val{…}) @ ForwardDiff /home/alexis/.julia/packages/ForwardDiff/PcZ48/src/jacobian.jl:23
││││┌ chunk_mode_jacobian(f::CTBase.var"#28#29"{}, x::Vector{…} where T<:Real, cfg::ForwardDiff.JacobianConfig{…} where {}) @ ForwardDiff /home/alexis/.julia/packages/ForwardDiff/PcZ48/src/jacobian.jl:213
│││││┌ seed!(duals::Array{…}, x::Vector{…} where T<:Real) where {} @ ForwardDiff /home/alexis/.julia/packages/ForwardDiff/PcZ48/src/apiutils.jl:45
││││││┌ seed!(duals::Array{…}, x::Vector{…} where T<:Real, seed::ForwardDiff.Partials{…}) where {} @ ForwardDiff /home/alexis/.julia/packages/ForwardDiff/PcZ48/src/apiutils.jl:45
│││││││┌ materialize!(dest::Array{…} where {}, bc::Base.Broadcast.Broadcasted{…} where T) @ Base.Broadcast ./broadcast.jl:911
││││││││┌ materialize!(::Base.Broadcast.DefaultArrayStyle{…}, dest::Array{…} where {}, bc::Base.Broadcast.Broadcasted{…} where T) @ Base.Broadcast ./broadcast.jl:914
│││││││││┌ copyto!(dest::Array{…} where {}, bc::Base.Broadcast.Broadcasted{…} where T) @ Base.Broadcast ./broadcast.jl:956
││││││││││┌ copyto!(dest::Array{…} where {}, bc::Base.Broadcast.Broadcasted{…} where F<:Type) @ Base.Broadcast ./broadcast.jl:1004
│││││││││││┌ getindex(bc::Base.Broadcast.Broadcasted{Nothing, Tuple{…}, Type{…}, <:Tuple{…}} where T, I::Int64) @ Base.Broadcast ./broadcast.jl:636
││││││││││││┌ _broadcast_getindex(bc::Base.Broadcast.Broadcasted{Nothing, Tuple{Base.OneTo{…}}, Type{T}, Union{}} where T, I::Int64) @ Base.Broadcast ./broadcast.jl:700
│││││││││││││┌ getproperty(x::Base.Broadcast.Broadcasted{Nothing, Tuple{Base.OneTo{Int64}}, Type{T}, Union{}} where T, f::Symbol) @ Base ./Base.jl:37
││││││││││││││ invalid builtin function call: Base.getfield(x::Base.Broadcast.Broadcasted{Nothing, Tuple{Base.OneTo{Int64}}, Type{T}, Union{}} where T, f::Symbol)
│││││││││││││└────────────────────
┌ CTBase.OptimalControlModel() @ CTBase /home/alexis/.julia/packages/Parameters/MK0O4/src/Parameters.jl:545
│┌ CTBase.OptimalControlModel(; model_expression::Nothing, initial_time::Nothing, initial_time_name::Nothing, final_time::Nothing, final_time_name::Nothing, time_name::Nothing, control_dimension::Nothing, control_components_names::Nothing, control_name::Nothing, state_dimension::Nothing, state_components_names::Nothing, state_name::Nothing, variable_dimension::Nothing, variable_components_names::Nothing, variable_name::Nothing, lagrange::Nothing, mayer::Nothing, criterion::Nothing, dynamics::Nothing, constraints::Dict{…}, dim_control_constraints::Nothing, dim_state_constraints::Nothing, dim_mixed_constraints::Nothing, dim_boundary_constraints::Nothing, dim_variable_constraints::Nothing, dim_control_range::Nothing, dim_state_range::Nothing, dim_variable_range::Nothing) @ CTBase /home/alexis/.julia/packages/Parameters/MK0O4/src/Parameters.jl:545
││ no matching method found `CTBase.OptimalControlModel(::Nothing, ::Nothing, ::Nothing, ::Nothing, ::Nothing, ::Nothing, ::Nothing, ::Nothing, ::Nothing, ::Nothing, ::Nothing, ::Nothing, ::Nothing, ::Nothing, ::Nothing, ::Nothing, ::Nothing, ::Nothing, ::Nothing, ::Dict{Symbol, Tuple}, ::Nothing, ::Nothing, ::Nothing, ::Nothing, ::Nothing, ::Nothing, ::Nothing, ::Nothing)`: OptimalControlModel(model_expression::Nothing, initial_time::Nothing, initial_time_name::Nothing, final_time::Nothing, final_time_name::Nothing, time_name::Nothing, control_dimension::Nothing, control_components_names::Nothing, control_name::Nothing, state_dimension::Nothing, state_components_names::Nothing, state_name::Nothing, variable_dimension::Nothing, variable_components_names::Nothing, variable_name::Nothing, lagrange::Nothing, mayer::Nothing, criterion::Nothing, dynamics::Nothing, constraints::Dict{Symbol, Tuple}, dim_control_constraints::Nothing, dim_state_constraints::Nothing, dim_mixed_constraints::Nothing, dim_boundary_constraints::Nothing, dim_variable_constraints::Nothing, dim_control_range::Nothing, dim_state_range::Nothing, dim_variable_range::Nothing)
│└────────────────────
┌ time!(ocp::CTBase.OptimalControlModel{…}; t0::Union{…}, tf::Union{…}, ind0::Union{…}, indf::Union{…}, name::Union{…}) where VT @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_model-setters.jl:366
│ no matching method found `kwcall(::@NamedTuple{digits::Int64}, ::typeof(round), ::Nothing)` (1/2 union split): Core.kwcall(NamedTuple{(:digits,)}(tuple(2)::Tuple{Int64})::@NamedTuple{digits::Int64}, CTBase.round, t0::Union{Nothing, Real})
└────────────────────
┌ time!(ocp::CTBase.OptimalControlModel{…}; t0::Union{…}, tf::Union{…}, ind0::Union{…}, indf::Union{…}, name::Union{…}) where VT @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_model-setters.jl:367
│ no matching method found `kwcall(::@NamedTuple{digits::Int64}, ::typeof(round), ::Nothing)` (1/2 union split): Core.kwcall(NamedTuple{(:digits,)}(tuple(2)::Tuple{Int64})::@NamedTuple{digits::Int64}, CTBase.round, tf::Union{Nothing, Real})
└────────────────────
┌ time!(ocp::CTBase.OptimalControlModel{…}; t0::Union{…}, tf::Union{…}, ind0::Union{…}, indf::Union{…}, name::Union{…}) where VT @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_model-setters.jl:370
│ no matching method found `CTBase.Index(::Nothing)` (1/2 union split): Index(ind0::Union{Nothing, Integer})
└────────────────────
┌ time!(ocp::CTBase.OptimalControlModel{…}; t0::Union{…}, tf::Union{…}, ind0::Union{…}, indf::Union{…}, name::Union{…}) where VT @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_model-setters.jl:373
│ no matching method found `getindex(::Nothing, ::Nothing)`, `getindex(::Nothing, ::Integer)` (2/4 union split): ((ocp::CTBase.OptimalControlModel).variable_components_names::Union{Nothing, Vector{String}})[ind0::Union{Nothing, Integer}]
└────────────────────
┌ time!(ocp::CTBase.OptimalControlModel{…}; t0::Union{…}, tf::Union{…}, ind0::Union{…}, indf::Union{…}, name::Union{…}) where VT @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_model-setters.jl:374
│ no matching method found `kwcall(::@NamedTuple{digits::Int64}, ::typeof(round), ::Nothing)` (1/2 union split): Core.kwcall(NamedTuple{(:digits,)}(tuple(2)::Tuple{Int64})::@NamedTuple{digits::Int64}, CTBase.round, tf::Union{Nothing, Real})
└────────────────────
┌ time!(ocp::CTBase.OptimalControlModel{…}; t0::Union{…}, tf::Union{…}, ind0::Union{…}, indf::Union{…}, name::Union{…}) where VT @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_model-setters.jl:378
│ no matching method found `CTBase.Index(::Nothing)` (1/2 union split): Index(indf::Union{Nothing, Integer})
└────────────────────
┌ time!(ocp::CTBase.OptimalControlModel{…}; t0::Union{…}, tf::Union{…}, ind0::Union{…}, indf::Union{…}, name::Union{…}) where VT @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_model-setters.jl:380
│ no matching method found `kwcall(::@NamedTuple{digits::Int64}, ::typeof(round), ::Nothing)` (1/2 union split): Core.kwcall(NamedTuple{(:digits,)}(tuple(2)::Tuple{Int64})::@NamedTuple{digits::Int64}, CTBase.round, t0::Union{Nothing, Real})
└────────────────────
┌ time!(ocp::CTBase.OptimalControlModel{…}; t0::Union{…}, tf::Union{…}, ind0::Union{…}, indf::Union{…}, name::Union{…}) where VT @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_model-setters.jl:381
│ no matching method found `getindex(::Nothing, ::Nothing)`, `getindex(::Nothing, ::Integer)` (2/4 union split): ((ocp::CTBase.OptimalControlModel).variable_components_names::Union{Nothing, Vector{String}})[indf::Union{Nothing, Integer}]
└────────────────────
┌ time!(ocp::CTBase.OptimalControlModel{…}; t0::Union{…}, tf::Union{…}, ind0::Union{…}, indf::Union{…}, name::Union{…}) where VT @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_model-setters.jl:384
│ no matching method found `CTBase.Index(::Nothing)` (1/2 union split): Index(ind0::Union{Nothing, Integer})
└────────────────────
┌ time!(ocp::CTBase.OptimalControlModel{…}; t0::Union{…}, tf::Union{…}, ind0::Union{…}, indf::Union{…}, name::Union{…}) where VT @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_model-setters.jl:385
│ no matching method found `CTBase.Index(::Nothing)` (1/2 union split): Index(indf::Union{Nothing, Integer})
└────────────────────
┌ time!(ocp::CTBase.OptimalControlModel{…}; t0::Union{…}, tf::Union{…}, ind0::Union{…}, indf::Union{…}, name::Union{…}) where VT @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_model-setters.jl:387
│ no matching method found `getindex(::Nothing, ::Nothing)`, `getindex(::Nothing, ::Integer)` (2/4 union split): ((ocp::CTBase.OptimalControlModel).variable_components_names::Union{Nothing, Vector{String}})[ind0::Union{Nothing, Integer}]
└────────────────────
┌ time!(ocp::CTBase.OptimalControlModel{…}; t0::Union{…}, tf::Union{…}, ind0::Union{…}, indf::Union{…}, name::Union{…}) where VT @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_model-setters.jl:388
│ no matching method found `getindex(::Nothing, ::Nothing)`, `getindex(::Nothing, ::Integer)` (2/4 union split): ((ocp::CTBase.OptimalControlModel).variable_components_names::Union{Nothing, Vector{String}})[indf::Union{Nothing, Integer}]
└────────────────────
┌ constraint!(ocp::CTBase.OptimalControlModel{…}, type::Symbol; rg::Union{…}, f::Union{…}, lb::Union{…}, ub::Union{…}, val::Union{…}, label::Symbol) where {} @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_model-setters.jl:507
│ no matching method found `(::Colon)(::Int64, ::Nothing)` (1/2 union split): @_63 = (1 CTBase.:(:) n::Union{Nothing, Integer})
└────────────────────
┌ constraint!(ocp::CTBase.OptimalControlModel{…}, type::Symbol; rg::Union{…}, f::Union{…}, lb::Union{…}, ub::Union{…}, val::Union{…}, label::Symbol) where {} @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_model-setters.jl:510
│ no matching method found `(::Colon)(::Int64, ::Nothing)` (1/2 union split): @_64 = (1 CTBase.:(:) m::Union{Nothing, Integer})
└────────────────────
┌ constraint!(ocp::CTBase.OptimalControlModel{…}, type::Symbol; rg::Union{…}, f::Union{…}, lb::Union{…}, ub::Union{…}, val::Union{…}, label::Symbol) where {} @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_model-setters.jl:513
│ no matching method found `(::Colon)(::Int64, ::Nothing)` (1/2 union split): @_65 = (1 CTBase.:(:) q::Union{Nothing, Integer})
└────────────────────
┌ constraint!(ocp::CTBase.OptimalControlModel{…}, type::Symbol; rg::Union{…}, f::Union{…}, lb::Union{…}, ub::Union{…}, val::Union{…}, label::Symbol) where {} @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_model-setters.jl:552
│ no matching method found `CTBase.BoundaryConstraint(::Nothing, ::Type{V} where V<:CTBase.VariableDependence)` (1/2 union split): BoundaryConstraint(f::Union{Nothing, Function}, V::Type{V} where V<:CTBase.VariableDependence)
└────────────────────
┌ constraint!(ocp::CTBase.OptimalControlModel{…}, type::Symbol; rg::Union{…}, f::Union{…}, lb::Union{…}, ub::Union{…}, val::Union{…}, label::Symbol) where {} @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_model-setters.jl:554
│ no matching method found `CTBase.ControlConstraint(::Nothing, ::Type{T} where T<:CTBase.TimeDependence, ::Type{V} where V<:CTBase.VariableDependence)` (1/2 union split): ControlConstraint(f::Union{Nothing, Function}, T::Type{T} where T<:CTBase.TimeDependence, V::Type{V} where V<:CTBase.VariableDependence)
└────────────────────
┌ constraint!(ocp::CTBase.OptimalControlModel{…}, type::Symbol; rg::Union{…}, f::Union{…}, lb::Union{…}, ub::Union{…}, val::Union{…}, label::Symbol) where {} @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_model-setters.jl:556
│ no matching method found `CTBase.StateConstraint(::Nothing, ::Type{T} where T<:CTBase.TimeDependence, ::Type{V} where V<:CTBase.VariableDependence)` (1/2 union split): StateConstraint(f::Union{Nothing, Function}, T::Type{T} where T<:CTBase.TimeDependence, V::Type{V} where V<:CTBase.VariableDependence)
└────────────────────
┌ constraint!(ocp::CTBase.OptimalControlModel{…}, type::Symbol; rg::Union{…}, f::Union{…}, lb::Union{…}, ub::Union{…}, val::Union{…}, label::Symbol) where {} @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_model-setters.jl:558
│ no matching method found `CTBase.MixedConstraint(::Nothing, ::Type{T} where T<:CTBase.TimeDependence, ::Type{V} where V<:CTBase.VariableDependence)` (1/2 union split): MixedConstraint(f::Union{Nothing, Function}, T::Type{T} where T<:CTBase.TimeDependence, V::Type{V} where V<:CTBase.VariableDependence)
└────────────────────
┌ constraint!(ocp::CTBase.OptimalControlModel{…}, type::Symbol; rg::Union{…}, f::Union{…}, lb::Union{…}, ub::Union{…}, val::Union{…}, label::Symbol) where {} @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_model-setters.jl:560
│┌ CTBase.VariableConstraint(f::Nothing) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/types.jl:849
││ no matching method found `convert(::Type{Function}, ::Nothing)`: @_3 = convert(fieldtype(VariableConstraint, 1)::Type{Function}, _3::Nothing)
│└────────────────────
┌  @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_model-setters.jl:644
│ no matching method found `String(::typeof(CTBase.objective))`: CTBase.String(objective)
└────────────────────
┌  @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_model-setters.jl:688
│ no matching method found `String(::typeof(CTBase.objective))`: CTBase.String(objective)
└────────────────────
┌ time_grid(sol::CTBase.OptimalControlSolution) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_solution-getters.jl:7
│ no matching method found `convert(::Type{Union{StepRangeLen, AbstractVector{<:Real}}}, ::Nothing)`: convert(TimesDisc, _3::Nothing)
└────────────────────
┌ initial_time_name(sol::CTBase.OptimalControlSolution) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_solution-getters.jl:15
│ no matching method found `convert(::Type{String}, ::Nothing)`: convert(CTBase.String, _3::Nothing)
└────────────────────
┌ final_time_name(sol::CTBase.OptimalControlSolution) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_solution-getters.jl:23
│ no matching method found `convert(::Type{String}, ::Nothing)`: convert(CTBase.String, _3::Nothing)
└────────────────────
┌ time_name(sol::CTBase.OptimalControlSolution) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_solution-getters.jl:31
│ no matching method found `convert(::Type{String}, ::Nothing)`: convert(CTBase.String, _3::Nothing)
└────────────────────
┌ control_dimension(sol::CTBase.OptimalControlSolution) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_solution-getters.jl:39
│ no matching method found `convert(::Type{Integer}, ::Nothing)`: convert(Dimension, _3::Nothing)
└────────────────────
┌ control_components_names(sol::CTBase.OptimalControlSolution) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_solution-getters.jl:47
│ no matching method found `convert(::Type{String}, ::Nothing)`, `convert(::Type{String}, ::Vector{String})` (2/2 union split): convert(CTBase.String, _3::Union{Nothing, Vector{String}})
└────────────────────
┌ control_name(sol::CTBase.OptimalControlSolution) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_solution-getters.jl:55
│ no matching method found `convert(::Type{String}, ::Nothing)`: convert(CTBase.String, _3::Nothing)
└────────────────────
┌ control(sol::CTBase.OptimalControlSolution) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_solution-getters.jl:68
│ no matching method found `convert(::Type{Function}, ::Nothing)`: convert(CTBase.Function, _3::Nothing)
└────────────────────
┌ state_dimension(sol::CTBase.OptimalControlSolution) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_solution-getters.jl:88
│ no matching method found `convert(::Type{Integer}, ::Nothing)`: convert(Dimension, _3::Nothing)
└────────────────────
┌ state_components_names(sol::CTBase.OptimalControlSolution) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_solution-getters.jl:96
│ no matching method found `convert(::Type{String}, ::Nothing)`, `convert(::Type{String}, ::Vector{String})` (2/2 union split): convert(CTBase.String, _3::Union{Nothing, Vector{String}})
└────────────────────
┌ state_name(sol::CTBase.OptimalControlSolution) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_solution-getters.jl:104
│ no matching method found `convert(::Type{String}, ::Nothing)`: convert(CTBase.String, _3::Nothing)
└────────────────────
┌ state(sol::CTBase.OptimalControlSolution) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_solution-getters.jl:117
│ no matching method found `convert(::Type{Function}, ::Nothing)`: convert(CTBase.Function, _3::Nothing)
└────────────────────
┌ variable_dimension(sol::CTBase.OptimalControlSolution) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_solution-getters.jl:137
│ no matching method found `convert(::Type{Integer}, ::Nothing)`: convert(Dimension, _3::Nothing)
└────────────────────
┌ variable_components_names(sol::CTBase.OptimalControlSolution) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_solution-getters.jl:145
│ no matching method found `convert(::Type{String}, ::Nothing)`, `convert(::Type{String}, ::Vector{String})` (2/2 union split): convert(CTBase.String, _3::Union{Nothing, Vector{String}})
└────────────────────
┌ variable_name(sol::CTBase.OptimalControlSolution) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_solution-getters.jl:153
│ no matching method found `convert(::Type{String}, ::Nothing)`: convert(CTBase.String, _3::Nothing)
└────────────────────
┌ variable(sol::CTBase.OptimalControlSolution) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_solution-getters.jl:164
│ no matching method found `convert(::Type{Union{Real, AbstractVector{<:Real}}}, ::Nothing)`: convert(Variable, _3::Nothing)
└────────────────────
┌ costate(sol::CTBase.OptimalControlSolution) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_solution-getters.jl:177
│ no matching method found `convert(::Type{Function}, ::Nothing)`: convert(CTBase.Function, _3::Nothing)
└────────────────────
┌ objective(sol::CTBase.OptimalControlSolution) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_solution-getters.jl:197
│ no matching method found `convert(::Type{Real}, ::Nothing)`: convert(ctNumber, _3::Nothing)
└────────────────────
┌ iterations(sol::CTBase.OptimalControlSolution) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_solution-getters.jl:205
│ no matching method found `convert(::Type{Int64}, ::Nothing)`: convert(CTBase.Int, _3::Nothing)
└────────────────────
┌ stopping(sol::CTBase.OptimalControlSolution) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_solution-getters.jl:213
│ no matching method found `convert(::Type{Symbol}, ::Nothing)`: convert(CTBase.Symbol, _3::Nothing)
└────────────────────
┌ message(sol::CTBase.OptimalControlSolution) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_solution-getters.jl:221
│ no matching method found `convert(::Type{String}, ::Nothing)`: convert(CTBase.String, _3::Nothing)
└────────────────────
┌ success(sol::CTBase.OptimalControlSolution) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_solution-getters.jl:229
│ no matching method found `convert(::Type{Bool}, ::Nothing)`: convert(CTBase.Bool, _3::Nothing)
└────────────────────
┌ boundary_constraints(sol::CTBase.OptimalControlSolution) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_solution-getters.jl:247
│ no matching method found `convert(::Type{Union{Real, AbstractVector{<:Real}}}, ::Nothing)`: convert(ctVector, _3::Nothing)
└────────────────────
┌ mult_boundary_constraints(sol::CTBase.OptimalControlSolution) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_solution-getters.jl:255
│ no matching method found `convert(::Type{Union{Real, AbstractVector{<:Real}}}, ::Nothing)`: convert(ctVector, _3::Nothing)
└────────────────────
┌ variable_constraints(sol::CTBase.OptimalControlSolution) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_solution-getters.jl:263
│ no matching method found `convert(::Type{Union{Real, AbstractVector{<:Real}}}, ::Nothing)`: convert(ctVector, _3::Nothing)
└────────────────────
┌ mult_variable_constraints(sol::CTBase.OptimalControlSolution) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_solution-getters.jl:271
│ no matching method found `convert(::Type{Union{Real, AbstractVector{<:Real}}}, ::Nothing)`: convert(ctVector, _3::Nothing)
└────────────────────
┌ mult_variable_box_lower(sol::CTBase.OptimalControlSolution) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_solution-getters.jl:279
│ no matching method found `convert(::Type{Union{Real, AbstractVector{<:Real}}}, ::Nothing)`: convert(ctVector, _3::Nothing)
└────────────────────
┌ mult_variable_box_upper(sol::CTBase.OptimalControlSolution) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_solution-getters.jl:287
│ no matching method found `convert(::Type{Union{Real, AbstractVector{<:Real}}}, ::Nothing)`: convert(ctVector, _3::Nothing)
└────────────────────
┌ control_constraints(sol::CTBase.OptimalControlSolution) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_solution-getters.jl:295
│ no matching method found `convert(::Type{Function}, ::Nothing)`: convert(CTBase.Function, _3::Nothing)
└────────────────────
┌ mult_control_constraints(sol::CTBase.OptimalControlSolution) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_solution-getters.jl:303
│ no matching method found `convert(::Type{Function}, ::Nothing)`: convert(CTBase.Function, _3::Nothing)
└────────────────────
┌ state_constraints(sol::CTBase.OptimalControlSolution) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_solution-getters.jl:311
│ no matching method found `convert(::Type{Function}, ::Nothing)`: convert(CTBase.Function, _3::Nothing)
└────────────────────
┌ mult_state_constraints(sol::CTBase.OptimalControlSolution) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_solution-getters.jl:319
│ no matching method found `convert(::Type{Function}, ::Nothing)`: convert(CTBase.Function, _3::Nothing)
└────────────────────
┌ mixed_constraints(sol::CTBase.OptimalControlSolution) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_solution-getters.jl:327
│ no matching method found `convert(::Type{Function}, ::Nothing)`: convert(CTBase.Function, _3::Nothing)
└────────────────────
┌ mult_mixed_constraints(sol::CTBase.OptimalControlSolution) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_solution-getters.jl:335
│ no matching method found `convert(::Type{Function}, ::Nothing)`: convert(CTBase.Function, _3::Nothing)
└────────────────────
┌ mult_state_box_lower(sol::CTBase.OptimalControlSolution) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_solution-getters.jl:343
│ no matching method found `convert(::Type{Function}, ::Nothing)`: convert(CTBase.Function, _3::Nothing)
└────────────────────
┌ mult_state_box_upper(sol::CTBase.OptimalControlSolution) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_solution-getters.jl:351
│ no matching method found `convert(::Type{Function}, ::Nothing)`: convert(CTBase.Function, _3::Nothing)
└────────────────────
┌ mult_control_box_lower(sol::CTBase.OptimalControlSolution) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_solution-getters.jl:359
│ no matching method found `convert(::Type{Function}, ::Nothing)`: convert(CTBase.Function, _3::Nothing)
└────────────────────
┌ mult_control_box_upper(sol::CTBase.OptimalControlSolution) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/optimal_control_solution-getters.jl:367
│ no matching method found `convert(::Type{Function}, ::Nothing)`: convert(CTBase.Function, _3::Nothing)
└────────────────────
┌ (::CTBase.var"#145#148")(h::Any, args::Vararg{Any}) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/ctparser_utils.jl:57
│┌ Expr(node::Base.JuliaSyntax.SyntaxNode) @ Base.JuliaSyntax /cache/build/builder-amdci4-4/julialang/julia-release-1-dot-10/base/JuliaSyntax/src/expr.jl:507
││┌ _to_expr(node::Base.JuliaSyntax.SyntaxNode) @ Base.JuliaSyntax /cache/build/builder-amdci4-4/julialang/julia-release-1-dot-10/base/JuliaSyntax/src/expr.jl:499
│││┌ head(node::Base.JuliaSyntax.SyntaxNode) @ Base.JuliaSyntax /cache/build/builder-amdci4-4/julialang/julia-release-1-dot-10/base/JuliaSyntax/src/syntax_tree.jl:108
││││┌ getproperty(node::Base.JuliaSyntax.SyntaxNode, name::Symbol) @ Base.JuliaSyntax /cache/build/builder-amdci4-4/julialang/julia-release-1-dot-10/base/JuliaSyntax/src/syntax_tree.jl:27
│││││┌ getproperty(x::Nothing, f::Symbol) @ Base ./Base.jl:37
││││││ type Nothing has no field raw: Base.getfield(x::Nothing, f::Symbol)
│││││└────────────────────
││┌ _to_expr(node::Base.JuliaSyntax.SyntaxNode) @ Base.JuliaSyntax /cache/build/builder-amdci4-4/julialang/julia-release-1-dot-10/base/JuliaSyntax/src/expr.jl:503
│││┌ _internal_node_to_Expr(source::Base.JuliaSyntax.SourceFile, srcrange::UnitRange{…}, head::Base.JuliaSyntax.SyntaxHead, childranges::Tuple{}, childheads::Tuple{}, args::Vector{…}) @ Base.JuliaSyntax /cache/build/builder-amdci4-4/julialang/julia-release-1-dot-10/base/JuliaSyntax/src/expr.jl:266
││││┌ getindex(t::Tuple{}, i::Int64) @ Base ./tuple.jl:31
│││││ BoundsError: attempt to access Tuple{} at index [1]: Base.getfield(t::Tuple{}, i::Int64, $(Expr(:boundscheck)))
││││└────────────────────
┌ parse!(p::Any, ocp::Any, e::Any) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/onepass.jl:75
│┌ parse!(p::Any, ocp::Any, e::Any; log::Bool) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/onepass.jl:164
││┌ map(f::CTBase.var"#170#171"{Bool}, A::Vector{Any}) @ Base ./abstractarray.jl:3285
│││┌ collect_similar(cont::Vector{…}, itr::Base.Generator{…} where F<:(CTBase.var"#170#171"{…})) @ Base ./array.jl:763
││││┌ _collect(c::Vector{…}, itr::Base.Generator{…} where F<:(CTBase.var"#170#171"{…}), ::Base.EltypeUnknown, isz::Base.HasShape{…}) @ Base ./array.jl:864
│││││┌ collect_to_with_first!(dest::Vector{…}, v1::Expr, itr::Base.Generator{…} where F<:(CTBase.var"#170#171"{…}), st::Int64) @ Base ./array.jl:869
││││││┌ setindex!(A::Vector{LineNumberNode}, x::Expr, i1::Int64) @ Base ./array.jl:1021
│││││││ no matching method found `convert(::Type{LineNumberNode}, ::Expr)`: convert(T::Type{LineNumberNode}, x::Expr)
││││││└────────────────────
│││││┌ collect_to_with_first!(dest::Vector{…}, v1::LineNumberNode, itr::Base.Generator{…} where F<:(CTBase.var"#170#171"{…}), st::Int64) @ Base ./array.jl:869
││││││┌ setindex!(A::Vector{Expr}, x::LineNumberNode, i1::Int64) @ Base ./array.jl:1021
│││││││ no matching method found `convert(::Type{Expr}, ::LineNumberNode)`: convert(T::Type{Expr}, x::LineNumberNode)
││││││└────────────────────
┌ var"@def"(__source__::LineNumberNode, __module__::Module, ocp::Any, e::Any) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/onepass.jl:514
│┌ var"@def"(__source__::LineNumberNode, __module__::Module, ocp::Any, e::Any, log::Bool) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/onepass.jl:518
││┌ kwcall(::@NamedTuple{}, ::typeof(CTBase.parse!), p::CTBase.ParsingInfo, ocp::Any, e::Any) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/onepass.jl:75
│││┌ parse!(p::CTBase.ParsingInfo, ocp::Any, e::Any; log::Bool) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/onepass.jl:114
││││┌ kwcall(::@NamedTuple{}, ::typeof(CTBase.p_constraint!), p::CTBase.ParsingInfo, ocp::Any, e1::Nothing, e2::Any, e3::Any) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/onepass.jl:274
│││││┌ kwcall(::@NamedTuple{}, ::typeof(CTBase.p_constraint!), p::CTBase.ParsingInfo, ocp::Any, e1::Nothing, e2::Any, e3::Any, label::Symbol) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/onepass.jl:274
││││││┌  @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/onepass.jl:289
│││││││┌ push!(a::Vector{Symbol}, item::Nothing) @ Base ./array.jl:1118
││││││││ no matching method found `convert(::Type{Symbol}, ::Nothing)`: convert(T::Type{Symbol}, item::Nothing)
│││││││└────────────────────
┌ (::CTBase.var"#parse_to_expr#190")(s::AbstractString) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/repl.jl:77
│┌ strip(s::AbstractString) @ Base ./strings/util.jl:433
││┌ rstrip(s::AbstractString) @ Base ./strings/util.jl:404
│││┌ rstrip(f::typeof(isspace), s::AbstractString) @ Base ./strings/util.jl:399
││││┌ iterate(::Base.Generator{…} where I<:(Base.Iterators.Zip{…} where Is<:Tuple{…})) @ Base ./generator.jl:44
│││││┌ iterate(z::Base.Iterators.Zip{…} where Is<:Tuple{…}) @ Base.Iterators ./iterators.jl:410
││││││┌ _zip_iterate_all(is::Tuple{…}, ss::Tuple{…}) @ Base.Iterators ./iterators.jl:418
│││││││┌ _zip_isdone(is::Tuple{…}, ss::Tuple{…}) @ Base.Iterators ./iterators.jl:449
││││││││┌ isdone(r::Base.Iterators.Reverse{Union{}}) @ Base ./io.jl:1187
│││││││││┌ getproperty(x::Base.Iterators.Reverse{Union{}}, f::Symbol) @ Base ./Base.jl:37
││││││││││ invalid builtin function call: Base.getfield(x::Base.Iterators.Reverse{Union{}}, f::Symbol)
│││││││││└────────────────────
┌ ct_repl(; debug::Any, verbose::Any) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/repl.jl:159
│┌ kwcall(::@NamedTuple{}, ::typeof(ReplMaker.initrepl), parser::CTBase.var"#parse_to_expr#190"{}) @ ReplMaker /home/alexis/.julia/packages/ReplMaker/ViCwA/src/ReplMaker.jl:42
││┌ initrepl(parser::CTBase.var"#parse_to_expr#190"{}; prompt_text::String, prompt_color::Symbol, start_key::Char, repl::Any, mode_name::String, show_function::Nothing, show_function_io::IO, valid_input_checker::typeof(ReplMaker.complete_julia), keymap::Dict{…}, completion_provider::REPL.REPLCompletionProvider, sticky_mode::Bool, startup_text::Bool) @ ReplMaker /home/alexis/.julia/packages/ReplMaker/ViCwA/src/ReplMaker.jl:64
│││┌ setup_interface(repl::REPL.LineEditREPL) @ REPL /cache/build/builder-amdci4-4/julialang/julia-release-1-dot-10/usr/share/julia/stdlib/v1.10/REPL/src/REPL.jl:971
││││┌ setup_interface(repl::REPL.LineEditREPL; hascolor::Bool, extra_repl_keymap::Dict) @ REPL /cache/build/builder-amdci4-4/julialang/julia-release-1-dot-10/usr/share/julia/stdlib/v1.10/REPL/src/REPL.jl:971
│││││┌ setup_interface(repl::REPL.LineEditREPL, hascolor::Bool, extra_repl_keymap::Dict) @ REPL /cache/build/builder-amdci4-4/julialang/julia-release-1-dot-10/usr/share/julia/stdlib/v1.10/REPL/src/REPL.jl:1053
││││││┌ REPL.REPLHistoryProvider(mode_mapping::Dict{Symbol, REPL.LineEdit.Prompt}) @ REPL /cache/build/builder-amdci4-4/julialang/julia-release-1-dot-10/usr/share/julia/stdlib/v1.10/REPL/src/REPL.jl:588
│││││││┌ REPL.REPLHistoryProvider(history::Vector{…}, file_path::String, history_file::Nothing, start_idx::Int64, cur_idx::Int64, last_idx::Int64, last_buffer::IOBuffer, last_mode::Nothing, mode_mapping::Dict{…}, modes::Vector{…}) @ REPL /cache/build/builder-amdci4-4/julialang/julia-release-1-dot-10/usr/share/julia/stdlib/v1.10/REPL/src/REPL.jl:577
││││││││┌ convert(::Type{Vector{Symbol}}, a::Vector{UInt8}) @ Base ./array.jl:665
│││││││││┌ Vector{Symbol}(x::Vector{UInt8}) @ Base ./array.jl:673
││││││││││┌ copyto_axcheck!(dest::Vector{Symbol}, src::Vector{UInt8}) @ Base ./abstractarray.jl:1177
│││││││││││┌ copyto!(dest::Vector{Symbol}, src::Vector{UInt8}) @ Base ./array.jl:385
││││││││││││┌ copyto!(dest::Vector{Symbol}, doffs::Int64, src::Vector{UInt8}, soffs::Int64, n::Int64) @ Base ./array.jl:363
│││││││││││││┌ _copyto_impl!(dest::Vector{Symbol}, doffs::Int64, src::Vector{UInt8}, soffs::Int64, n::Int64) @ Base ./array.jl:376
││││││││││││││┌ unsafe_copyto!(dest::Vector{Symbol}, doffs::Int64, src::Vector{UInt8}, soffs::Int64, n::Int64) @ Base ./array.jl:353
│││││││││││││││┌ _unsafe_copyto!(dest::Vector{Symbol}, doffs::Int64, src::Vector{UInt8}, soffs::Int64, n::Int64) @ Base ./array.jl:299
││││││││││││││││┌ setindex!(A::Vector{Symbol}, x::UInt8, i1::Int64) @ Base ./array.jl:1021
│││││││││││││││││ no matching method found `convert(::Type{Symbol}, ::UInt8)`: convert(T::Type{Symbol}, x::UInt8)
││││││││││││││││└────────────────────
│││││┌ setup_interface(repl::REPL.LineEditREPL, hascolor::Bool, extra_repl_keymap::Dict) @ REPL /cache/build/builder-amdci4-4/julialang/julia-release-1-dot-10/usr/share/julia/stdlib/v1.10/REPL/src/REPL.jl:1082
││││││┌ setup_search_keymap(hp::REPL.REPLHistoryProvider) @ REPL.LineEdit /cache/build/builder-amdci4-4/julialang/julia-release-1-dot-10/usr/share/julia/stdlib/v1.10/REPL/src/LineEdit.jl:2208
│││││││┌ keymap(keymaps::Vector{Dict{Any, Any}}) @ REPL.LineEdit /cache/build/builder-amdci4-4/julialang/julia-release-1-dot-10/usr/share/julia/stdlib/v1.10/REPL/src/LineEdit.jl:1817
││││││││┌ keymap_unify(keymaps::Vector{Dict{Any, Any}}) @ REPL.LineEdit /cache/build/builder-amdci4-4/julialang/julia-release-1-dot-10/usr/share/julia/stdlib/v1.10/REPL/src/LineEdit.jl:1795
│││││││││┌ keymap_merge(target::Dict{Char, Any}, source::Dict{Any, Any}) @ REPL.LineEdit /cache/build/builder-amdci4-4/julialang/julia-release-1-dot-10/usr/share/julia/stdlib/v1.10/REPL/src/LineEdit.jl:1765
││││││││││┌ normalize_key(key::String) @ REPL.LineEdit /cache/build/builder-amdci4-4/julialang/julia-release-1-dot-10/usr/share/julia/stdlib/v1.10/REPL/src/LineEdit.jl:1541
│││││││││││┌ indexed_iterate(I::Nothing, i::Int64) @ Base ./tuple.jl:95
││││││││││││ no matching method found `iterate(::Nothing)`: x = iterate(I::Nothing)
│││││││││││└────────────────────
│││││││││││┌ indexed_iterate(I::Nothing, i::Int64, state::Int64) @ Base ./tuple.jl:100
││││││││││││ no matching method found `iterate(::Nothing, ::Int64)`: x = iterate(I::Nothing, state::Int64)
│││││││││││└────────────────────
┌ show(io::IO, ::MIME{Symbol("text/plain")}, ocp::CTBase.OptimalControlModel) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/print.jl:50
│ no matching method found `__print(::Nothing, ::IO, ::Int64)` (1/2 union split): return#1250 = CTBase.__print(code::Union{Nothing, Expr}, io::IO, tab::Int64)
└────────────────────
┌ show(io::IO, ::MIME{Symbol("text/plain")}, ocp::CTBase.OptimalControlModel) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/print.jl:76
│ no matching method found `*(::Nothing, ::String)` (1/2 union split): @_79 = (t_name::Union{Nothing, String} CTBase.:* ", ")
└────────────────────
┌ show(io::IO, ::MIME{Symbol("text/plain")}, ocp::CTBase.OptimalControlModel) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/print.jl:77
│ no matching method found `*(::String, ::Nothing)` (1/2 union split): @_80 = (", " CTBase.:* v_name::Union{Nothing, String})
└────────────────────
┌ show(io::IO, ::MIME{Symbol("text/plain")}, ocp::CTBase.OptimalControlModel) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/print.jl:80
│┌ *(::Union{…}, ::String, ::Union{…}, ::String, ::Union{…}, ::String, ::Union{…}, ::String, ::String) @ Base ./operators.jl:587
││┌ afoldl(::typeof(*), ::String, ::String, ::Nothing, ::String, ::Nothing, ::String, ::String) @ Base ./operators.jl:545
│││ no matching method found `*(::String, ::Nothing)`: y = op::typeof(*)(y::String, (bs::Tuple{String, Nothing, String, Nothing, String, String})[i::Int64]::Nothing)
││└────────────────────
││┌ afoldl(::typeof(*), ::String, ::String, ::String, ::String, ::Nothing, ::String, ::String) @ Base ./operators.jl:547
│││ no matching method found `*(::String, ::Nothing)`: y = op::typeof(*)(y::String, (bs::Tuple{String, String, String, Nothing, String, String})[i::Int64]::Nothing)
││└────────────────────
││┌ afoldl(::typeof(*), ::String, ::String, ::Nothing, ::String, ::String, ::String, ::String) @ Base ./operators.jl:545
│││ no matching method found `*(::String, ::Nothing)`: y = op::typeof(*)(y::String, (bs::Tuple{String, Nothing, Vararg{String, 4}})[i::Int64]::Nothing)
││└────────────────────
┌ show(io::IO, ::MIME{Symbol("text/plain")}, ocp::CTBase.OptimalControlModel) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/print.jl:82
│┌ *(::String, ::Nothing, ::String, ::Nothing, ::String, ::String) @ Base ./operators.jl:587
││ no matching method found `*(::String, ::Nothing)`: (a::String * b::Nothing)
│└────────────────────
│┌ *(::String, ::String, ::String, ::Nothing, ::String, ::String) @ Base ./operators.jl:587
││┌ afoldl(::typeof(*), ::String, ::Nothing, ::String, ::String) @ Base ./operators.jl:544
│││ no matching method found `*(::String, ::Nothing)`: y = op::typeof(*)(y::String, (bs::Tuple{Nothing, String, String})[i::Int64]::Nothing)
││└────────────────────
┌ show(io::IO, ::MIME{Symbol("text/plain")}, ocp::CTBase.OptimalControlModel) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/print.jl:112
│ no matching method found `*(::String, ::Nothing)` (1/2 union split): ("        " CTBase.:* x_name::Union{Nothing, String})
└────────────────────
┌ show(io::IO, ::MIME{Symbol("text/plain")}, ocp::CTBase.OptimalControlModel) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/print.jl:137
│ no matching method found `ctupperscripts(::Nothing)` (1/2 union split): @_81 = ctupperscripts(x_dim::Union{Nothing, Integer})
└────────────────────
┌ show(io::IO, ::MIME{Symbol("text/plain")}, ocp::CTBase.OptimalControlModel) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/print.jl:138
│ no matching method found `ctupperscripts(::Nothing)` (1/2 union split): @_82 = ctupperscripts(u_dim::Union{Nothing, Integer})
└────────────────────
┌ show(io::IO, ::MIME{Symbol("text/plain")}, ocp::CTBase.OptimalControlModel) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/print.jl:142
│┌ *(a::Nothing, b::String, c::Nothing, xs::String) @ Base ./operators.jl:587
││ no matching method found `*(::Nothing, ::String)`: (a::Nothing * b::String)
│└────────────────────
│┌ *(a::String, b::String, c::Nothing, xs::String) @ Base ./operators.jl:587
││ no matching method found `*(::String, ::Nothing)`: ((a::String * b::String)::String * c::Nothing)
│└────────────────────
┌ show(io::IO, ::MIME{Symbol("text/plain")}, ocp::CTBase.OptimalControlModel) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/print.jl:147
│ no matching method found `(::Colon)(::Int64, ::Nothing)` (1/2 union split): (1 CTBase.:(:) x_dim::Union{Nothing, Integer})
└────────────────────
┌ show(io::IO, ::MIME{Symbol("text/plain")}, ocp::CTBase.OptimalControlModel) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/print.jl:163
│ no matching method found `(::Colon)(::Int64, ::Nothing)` (1/2 union split): (1 CTBase.:(:) u_dim::Union{Nothing, Integer})
└────────────────────
┌ show(io::IO, ::MIME{Symbol("text/plain")}, ocp::CTBase.OptimalControlModel) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/print.jl:174
│ no matching method found `ctupperscripts(::Nothing)` (1/2 union split): @_83 = ctupperscripts(v_dim::Union{Nothing, Integer})
└────────────────────
┌ show(io::IO, ::MIME{Symbol("text/plain")}, ocp::CTBase.OptimalControlModel) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/print.jl:181
│ no matching method found `*(::Nothing, ::String)` (1/2 union split): v_name_space = (v_name_space::Union{Nothing, String} CTBase.:* " = (")
└────────────────────
┌ show(io::IO, ::MIME{Symbol("text/plain")}, ocp::CTBase.OptimalControlModel) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/print.jl:182
│ no matching method found `(::Colon)(::Int64, ::Nothing)` (1/2 union split): (1 CTBase.:(:) v_dim::Union{Nothing, Integer})
└────────────────────
┌ show(io::IO, ::MIME{Symbol("text/plain")}, ocp::CTBase.OptimalControlModel) @ CTBase /home/alexis/.julia/packages/CTBase/H6Hw7/src/print.jl:233
│┌ kwcall(::@NamedTuple{}, ::typeof(PrettyTables.pretty_table), io::IO, data::Matrix{…}) @ PrettyTables /home/alexis/.julia/packages/PrettyTables/f6dXb/src/print.jl:794
││┌ pretty_table(io::IO, data::Matrix{…}; header::Vector{…}, kwargs::@Kwargs{}) @ PrettyTables /home/alexis/.julia/packages/PrettyTables/f6dXb/src/print.jl:825
│││┌ kwcall(::@NamedTuple{}, ::typeof(PrettyTables._print_table), io::IO, data::Matrix{…}) @ PrettyTables /home/alexis/.julia/packages/PrettyTables/f6dXb/src/print.jl:934
││││┌ _print_table(io::IO, data::Matrix{…}; alignment::Symbol, backend::Val{…}, cell_alignment::Nothing, cell_first_line_only::Bool, compact_printing::Bool, formatters::Nothing, header::Tuple{…}, header_alignment::Symbol, header_cell_alignment::Nothing, limit_printing::Bool, max_num_of_columns::Int64, max_num_of_rows::Int64, renderer::Symbol, row_labels::Nothing, row_label_alignment::Symbol, row_label_column_title::String, row_number_alignment::Symbol, row_number_column_title::String, show_header::Bool, show_row_number::Bool, show_subheader::Bool, title::String, title_alignment::Symbol, kwargs::@Kwargs{}) @ PrettyTables /home/alexis/.julia/packages/PrettyTables/f6dXb/src/print.jl:1059
│││││┌ kwcall(::@NamedTuple{}, ::typeof(PrettyTables._print_table_with_text_back_end), pinfo::PrettyTables.PrintInfo) @ PrettyTables /home/alexis/.julia/packages/PrettyTables/f6dXb/src/backends/text/text_backend.jl:8
││││││┌ _print_table_with_text_back_end(pinfo::PrettyTables.PrintInfo; alignment_anchor_fallback::Symbol, alignment_anchor_fallback_override::Dict{…}, alignment_anchor_regex::Dict{…}, autowrap::Bool, body_hlines::Vector{…}, body_hlines_format::Nothing, continuation_row_alignment::Symbol, crop::Symbol, crop_subheader::Bool, columns_width::Int64, display_size::Tuple{…}, equal_columns_width::Bool, ellipsis_line_skip::Int64, highlighters::Tuple{…}, hlines::Nothing, linebreaks::Bool, maximum_columns_width::Int64, minimum_columns_width::Int64, newline_at_end::Bool, overwrite::Bool, reserved_display_lines::Int64, show_omitted_cell_summary::Bool, sortkeys::Bool, tf::PrettyTables.TextFormat, title_autowrap::Bool, title_same_width_as_table::Bool, vcrop_mode::Symbol, vlines::Nothing, border_crayon::Crayons.Crayon, header_crayon::Crayons.Crayon, omitted_cell_summary_crayon::Crayons.Crayon, row_label_crayon::Crayons.Crayon, row_label_header_crayon::Crayons.Crayon, row_number_header_crayon::Crayons.Crayon, subheader_crayon::Crayons.Crayon, text_crayon::Crayons.Crayon, title_crayon::Crayons.Crayon) @ PrettyTables /home/alexis/.julia/packages/PrettyTables/f6dXb/src/backends/text/text_backend.jl:145
│││││││┌ _process_hlines(ptable::PrettyTables.ProcessedTable, hlines::Vector{Symbol}) @ PrettyTables /home/alexis/.julia/packages/PrettyTables/f6dXb/src/misc.jl:319
││││││││┌ replace(::Vector{Symbol}, ::Pair{Symbol, Int64}, ::Pair{Symbol, Int64}, ::Pair{Symbol, Int64}) @ Base ./set.jl:686
│││││││││┌ replace(::Vector{Symbol}, ::Pair{Symbol, Int64}, ::Pair{Symbol, Int64}, ::Pair{Symbol, Int64}; count::Nothing) @ Base ./set.jl:690
││││││││││┌ replace_pairs!(res::Vector, A::Vector{Symbol}, count::Int64, old_new::Tuple{Pair{…}, Pair{…}, Pair{…}}) @ Base ./set.jl:616
│││││││││││┌ _replace!(new::Base.var"#new#395"{Tuple{Pair{}, Pair{}, Pair{}}}, res::Vector, A::Vector{Symbol}, count::Int64) @ Base ./set.jl:798
││││││││││││┌ setindex!(A::Vector{Symbol}, x::Int64, i1::Int64) @ Base ./array.jl:1021
│││││││││││││ no matching method found `convert(::Type{Symbol}, ::Int64)`: convert(T::Type{Symbol}, x::Int64)
││││││││││││└────────────────────

@jbcaillau
Copy link
Member Author

@jbcaillau I will probably use multiple dispatch so that the compiler knows the output type for each combination:

__view(x::Number, rg) = x 
__view(x::AbstractVector, rg::Integer) = x[rg]
__view(x::AbstractVector, rg::UnitRange) = view(x, rg)

Good point for multiple dispatch (instead of runtime if).

But it's quite cheap to use an array of length 1 instead of a scalar rhs, so it could be more efficient to a vector in all-cases such that the compiler can infer the type of each parameter and variable.

Sure. Actually, we want to allow the user to be able to use a scalar instead of a length one vector, as being compelled to write x[1] instead of x for a scalar would not be so nice.

Instead of view, you could also use the 5-arguments version of copyto!:

A = zeros(10)
B = [i for i = 1:10]
start_A = 5
start_B = 3
N = 4
copyto!(A, start_A, B, start_B, N)
10-element Vector{Float64}:
0.0
0.0
0.0
0.0
3.0
4.0
5.0
6.0
0.0
0.0

👍🏽 nice. I see it also works for scalar rhs. one con, though: in a high level language such as Julia, should be the compiler task to translate sth like x[…] = y[…] into an efficient copy.

@jbcaillau
Copy link
Member Author

@ocots @jbcaillau Before that I forgot, you are using quite often a foo::Union{Nothing, ...} inside your structures for the type of the attributes. The compiler doesn't like that and it leads to additional allocations because it needs to check at runtime that it's a Nothing or not. You can change that for foo::T and at the top of your structure T <: Union{Nothing, ...}.

@amontoison

  • these unions are with Nothing and various types (not a single one)
  • some fields might be nothing, some not

does your remark still apply?

@amontoison
Copy link
Contributor

amontoison commented Sep 6, 2024

@ocots @jbcaillau Before that I forgot, you are using quite often a foo::Union{Nothing, ...} inside your structures for the type of the attributes. The compiler doesn't like that and it leads to additional allocations because it needs to check at runtime that it's a Nothing or not. You can change that for foo::T and at the top of your structure T <: Union{Nothing, ...}.

@amontoison

* these unions are with `Nothing` and various types (not a single one)

* some fields might be `nothing`, some not

does your remark still apply?

Yes, you just need to parameterize your structures with the types

struct OptControl{T1, T2, ..., TN}
field1::T1,
field2::Int64,
field3::T2,
field4::Float64,
...
fieldM::TN
end

You can still add restriction on Ti with Ti <: Union{...}.

@amontoison
Copy link
Contributor

amontoison commented Sep 6, 2024

It's blascopy!.

stride provided but no more starting index to cover general slices i:j:k. bref

julia> let x = zeros(2)
       y = ones(2)
       println(@allocated blascopy!(2, y, 1, x, 1))
       println(x)
       end
0
[1.0, 1.0]

julia> let x = zeros(4)
       y = ones(2)
       println(@allocated blascopy!(2, y, 1, view(x, 2), 1))
       println(x)
       end
48
[0.0, 1.0, 1.0, 0.0]

Because technically you can give the pointer of the coefficient x[i] to blascopy! Instead of x[1]. It will call a Fortran routine so x and y are passed by pointer and it can start at any position.

@jbcaillau
Copy link
Member Author

jbcaillau commented Sep 6, 2024

@amontoison

julia> let x = zeros(4)
                     println(@allocated x[1:2] = cos.(x[3:4].^2) .+ x[1])
                     end
176

julia> let x = zeros(4)
                     println(@allocated @views x[1:2] = cos.(x[3:4].^2) .+ x[1])
                     end
96

julia> let x = zeros(4)
                     println(@allocated x[1:2] .= cos.(x[3:4].^2) .+ x[1])
                     end
80

julia> let x = zeros(4)
                     println(@allocated @views x[1:2] .= cos.(x[3:4].^2) .+ x[1])
                     end
0

let x = zeros(4)
                     println(@allocated @views x[1:2] .= cos.(x[2:3].^2) .+ x[1]) # Overlap
                     end
80

julia> let x = zeros(4)
                     println(@allocated copyto!(x, 1, cos.(x[3:4].^2) .+ x[1], 1, 2))
                     end
176

julia> let x = zeros(4)
                     println(@allocated copyto!(x, 1, cos.(x[2:3].^2) .+ x[1], 1, 2)) # Overlap
                     end
176

julia> let x = zeros(4)
                     println(@allocated @views copyto!(x, 1, cos.(x[3:4].^2) .+ x[1], 1, 2))
                     end
96

julia> let x = zeros(4)
                     println(@allocated @views copyto!(x, 1, cos.(x[2:3].^2) .+ x[1], 1, 2)) # Overlap
                     end
96

@jbcaillau
Copy link
Member Author

jbcaillau commented Sep 6, 2024

@PierreMartinon please review before merging and testing in CTDirect.jl with updated nlp_constraints!

NB.

  •  @jbcaillau add tests on nlp_constraints! with an in place ocp in test_model.jl

@jbcaillau jbcaillau marked this pull request as ready for review September 6, 2024 23:43
@jbcaillau
Copy link
Member Author

jbcaillau commented Sep 8, 2024

@jbcaillau

  • check to use (for generated code in onepass, for in place functions in tests, as in test_model...) .= with @views as the combination allows to treat uniformly and efficiently vectors and scalar (letting the compiler doing its best); e.g.
(r, x) -> (@views r[:] .= u * cos.(x[1:2]); nothing)
  • in particular, replace r[:] .= __view(...) by @views r[:] .= ... in model setters / getters
  • use @views $r[:] .= $expr in onepass generated functions
  • replace view(x, i:j:k) args in calls by @view(x[i:j:k]) for further improvement (NB : always a single slice/genuine view, no need for @views)
  • [ ] remove internal use of Index, including time! cases (there, use Ref - check before with @PierreMartinon for CTDirect.jl impact) postponed to [Feature] Remove Index type #289

NB. contrary to @view, @views used on a single element (not a length one slice) of a vector does not return a view (and so does not allow side effects):

julia> z = [0.]
1-element Vector{Float64}:
 0.0

julia> @view z[1]
0-dimensional view(::Vector{Float64}, 1) with eltype Float64:
0.0

julia> @views z[1]
0.0

@jbcaillau jbcaillau merged commit 7234fa2 into main Sep 9, 2024
9 checks passed
@jbcaillau jbcaillau deleted the 232-preparing-for-inplace-nlp branch September 9, 2024 16:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Preparing for inplace NLP
5 participants