I’m trying to use this unofficial CasADi interface in Julia since the official interface seems to be a long way from working (couldn’t get it installed in Julia 1.10, as stated in Project.toml). I’m having a hard time handling the fact that CasADi’s main number type, SX, is supposed to behave both as a scalar and as an array, since this leads to vector expressions mixing Array{SX} and SX. As an example, the following code errors:
using CasADi
v = SX("v", 2)
[v[2]; v[1]] + v
because it actually tries to add a Vector{SX} to a SX, thought to be a scalar (since SX <: Real):
ERROR: MethodError: no method matching +(::Vector{SX}, ::SX)
For element-wise addition, use broadcasting with dot syntax: array .+ scalar
The function + exists, but no method is defined for this combination of argument types.
It’d contradict what the constructor is documented to do, and it wouldn’t affect your example anyway because the N-dimensional type was never called, the 1-dimensional one was.
This also contradicts the documented behavior, and see help?> [] for all the functions you’d have to extend.
My two cents, steer clear from hacking base Julia’s Array constructors and syntax because it’s designed for generic element types of Array, not generic array types. SX(...) is implemented and looks fairly simple. Your convertSX has a reasonable fallback to dodge what the SX call does to other arrays, but convert(SX, ...) is already there if you need it to error instead.
What do you need to happen here, exactly? The wrapper does SX(...) conversion already.
Type promotion is based on a conventional ordering of nominally broadening types (broadening does not imply maintaining numeric precision). There’s no such convention for dense multidimensional arrays and CasADi types.
I would want scalar_SX * I(3) to return an SX expression, instead of a Diagonal{...}.
I gather this convertSX is the most practical approach to dodge this (rather unfortunate) decision of treating SX as a Real, which prevents a lot of convenient vector operations.
I noticed later that packages that introduce new vector types, such as StaticArrays, always introduce a different bracket operator, such as SA[...] due to the limitations you mentioned.
julia> using CasADi, LinearAlgebra; typeof(SX("v") * I(3))
SX
It’s not common in my experience, and it’s basic indexing syntax lowering to getindex(SA, ...). The type (or singleton) SA serves to dispatch to a nominal getindex method that forwards to another type’s constructor. Base Julia uses this for setting explicit element types of Array e.g. Int[1,2,3]. StaticArrays.SA does this for instantiating SVectors with inferred element types e.g. SA[1,2,3] or explicit element types e.g. SA{Int}[1,2.0,3]. SA is itself an instantiable type e.g. SA{Int}(), but these instances aren’t intended to be used anywhere and justify SA[...] not instantiating Array{SA}. I don’t know how this would work across the PythonCall barrier and don’t expect it to help with most of the proposed type features here, but I’m just explaining this in case you’re interested in implementing a bracket operator for some convenience.
Ah, I’m using the SciML fork of CasADi in the General registry, v1.3.0. Reused UUID, so probably intended as a successor. Funnily enough, the fork’s v0.2.0 isn’t capable of SX("x") * I(3) at all; that’s how much it was reworked.