Seeking an "isvector" function

What do you want it to do?

In you example you had the same body for all three functions, so if that is how you will use it you could just create a union of the types you want to allow as

isvector(x::Union{Array{<:Number}, Number}) = count(>(1), size(x)) ≤ 1

or something like that which should catch all the cases.

If you want to handle the three cases differently you just create three methods that will then be used for the different types

isvector(x::Vector{<:Number}) = true
isvector(x::Array{<:Number}) = count(>(1), size(x)) ≤ 1
isvector(x::Number) = false
2 Likes

Maybe I do not understand your proposal to define a Union here is my code that work currently only for vectors:

function MyLib_isvector(_val::Union{Vector{<:Number}, Array{<:Number}, Number})
    return count(>(1), size(_val)) ≤ 1
end  

mat2D = [1 2 3; 4 5 6]
mat1D = [1 2 3]
vec_  = [1,2,3]

isvector = MyLib_isvector(mat2D)
isvector = MyLib_isvector(mat1D) 
isvector = MyLib_isvector(vec_) 

It might very well be that I just don’t understand what you want.

When I run the code you have I get false, true, true and I thought that was what you wanted? As long as there is at most one dimension that is larger than 1, it is a vector? Running it on a number I also get true which could be what you want according to that definition?

What is it that only work for vectors for you? What is the expected output?

The advice in the above discussion is that one doesn’t need, and shouldn’t use, a function that detects if something is similar to a vector. Instead one should use broadcasting.

Maybe your use case is different, so if you can say something more about it, perhaps you can get better advice. What do you need this for?

2 Likes

I do not know exactly why I had an error message.
After a restart it works fine :slight_smile:
Thanks a lot!

I do not understand why a function might be a bad idea and how the alternative via broadcast looks like exactly. During testing I saw that the function MyLib_isvector in the initial version could not distinguish between a scalar and a vector, therefore, I added the proposal from @fredrikekre to use isa(x, AbstractVector), here is the result:

function MyLib_isvector(_val::Union{Vector{<:Number}, Array{<:Number}, Number})
    if count(>(1), size(_val)) ≤ 1
        if isa(_val, AbstractVector)
            _isvector = true
        else
            _isvector = false
        end
    else
        _isvector = false
    end
    return _isvector
end

Don’t you want simply something like this?

julia> isvector(val) = false
isvector (generic function with 1 method)

julia> isvector(val::AbstractVector) = true
isvector (generic function with 2 methods)

julia> isvector(1)
false

julia> isvector([1,2,3])
true

julia> isvector(zeros(3,3))
false

5 Likes

That is really cool!!!
And not easy to understand for me.
The first method defines the standard / default value.
And the second is going to be taken, if the input parameter format belongs to the group of AbstractVector. Is this a correct summary?
Currently, the function isvector()is not defined, but it could be, that in one package
or in an upcoming version of Julia this function exist.
I wonder, if there is a way to restrict the definition only to these situations, in which the command does not already exist?

The most specific method is called for the input given. It is the basis of how multiple dispatch works in Julia:

https://docs.julialang.org/en/v1/manual/methods/

1 Like

By bad idea, I mean that it’s almost certainly not the right way to solve most problems in Julia. In Matlab such a function is useful, and does exist, I think, but in Julia it does not, and will probably never exist in the Base language.

I cannot imagine any problem where such a function would be useful in Julia, because you would either use multiple dispatch or broadcasting to solve it. If you look further up in this thread there is an example of how to solve a problem with broadcasting.

I suspect this is an example of an XY-problem If you explain what you want to achieve beyond the vector detection, we could probably help you find a better way.

1 Like

In may case the fft() failed the error message was:

ERROR: FFTW could not create plan

I figured out the input vector was constructed via a multiplication:

Yk = fft(X_ .* Y_)

In some situations X_ became a matrix(n, 1)
This resulted sometimes (sic!) in the error above, the same occurred in other situations:
Vector is fine matrix(n, 1) fails, in such cases a function “isvector()” is quite handy.

You can perhaps restrict X_ to be a vector at an earlier point. The problem probably lies somewhere else, the real question is how does X_ sometimes end up as a matrix?

But if you know that X_ is always a vector or an Nx1 matrix, you can simply do

fft(vec(X_) .* Y_) 

or fft(vec(X_ .* Y_) ). The vec operation is nearly zero cost.

the command vec() is in my top-20 list of commands .-)
This is the way I dial with such situations.
The reason is in this example a third party module.

For the purpose of stem-plots by means of the package “PlotlyJS”
I need to ensure that the input is of type vector, this is true also if there is only one stem (one tuple x,y) I would like to plot.
Now I thought of a function that ensures that x,y-Values are each of the type Vector{} for this purpose I wrote a !-function that should do the job, but I have not figured out what the trick is with these functions that can modify their arguments. Below my code:

# --- "isvector()" one function with two methods
isvector(val) = false # definition of 1st method of func isvector()
isvector(val::AbstractVector) = true # definition of 2nd method of func isvector() 
# --- convertion function, be sure a one element variable is a one element vector:
function _transform_scalar_to_one_element_vec! end
function _transform_scalar_to_one_element_vec!(_oneNumber::Union{Vector{<:Number}, Array{<:Number}, Number})
    _isvector(val) = false # definition of 1st method of func isvector()
    _isvector(val::AbstractVector) = true # definition of 2nd method of func isvector() 
    # --- check that variable consists only of one number:
    only(_oneNumber)
    if ~_isvector(_oneNumber) 
        _oneNumber = [_oneNumber]
        println("_transform_scalar_to_one_element_vec!: converted to vector")
    else
        println("_transform_scalar_to_one_element_vec!: is already vector")
    end
    return _oneNumber
end
a = 1.1
isvector(a)
b = _transform_scalar_to_one_element_vec!(a)
isvector(a)
typeof(a)
isvector(b)

This seems very awkward. But if you must:

ensure_singular_vec(x) = [only(x)]
3 Likes

Agreed, quite awkward. How about something like this instead?

function my_stem_plot(x::AbstractVector, y::AbstractVector)
  #  Do the plotting here
end

my_stem_plot(x::Number, y::Number) = my_stem_plot([x], [y])
my_stem_plot(x::Number, y) = my_stem_plot([x], y)
my_stem_plot(x, y::Number) = my_stem_plot(x, [y])
my_stem_plot(x::Tuple) = my_stem_plot(x...)

Edit: Added a method to disambiguate the case where both arguments are scalars.

2 Likes

As a side note, this is not a proper use of !, since you aren’t mutating the input. Also, ! is meaningless with number inputs, since they are immutable, yet you can input that into your function because of your wide type signature.

2 Likes

BTW, this is the same as Union{Array{<:Number}, Number}.

2 Likes

I do not have a clue, why your function is awkward; this might be related to my limited English skills. Your code works fine for my! Thanks :slight_smile:

Thanks a lot! :slight_smile: