How to make `[0] == 0`?

julia> 2 .- [1 1] * [1; 1] == 0
false

This means in Julia [0] != 0. Although I can understand this rule, I feel it inconvenient to use. Do I have to build awareness of this kind and to code carefully when using Julia, or is there any workaround to make it more convenient?

Thanks

It really should have been an error to compare two different types like that, but it’s too late now. Anyway yeah you just have to be careful.

6 Likes

You could use iszero(arr). link

5 Likes

Unlike, R or Matlab, Julia does not identify vectors and scalars as they are fundamentally different data structures, e.g., vectors are mutable, but scalars not. Thus, you need to take a bit more care about that.

  • If you happen to know that your vector/matrix is actually a singleton, you can use only to extract the value:
    julia> only(2 .- [1 1] * [1; 1]) == 0
    true
    
  • The behaviour of R can be replicated via broadcasting:
    julia> 2 .- [1 1] * [1; 1] .== 0
    1-element BitVector:
       1
    
     julia> all(2 .- [1 1] * [1; 1] .== 0)
     true
    
    The all(...) phrase does basically the same as iszero when called on a vector.
9 Likes

you could try this form [itr...]', as was pointed out to me in a recent post where I had hastily confused the two expressions

2 .- [1; 1]' * [1; 1] == 0

in the place of


2 .- [1 1] * [1; 1] == 0
1 Like

One other option is to write your code in a way that you’re guaranteed to get a scalar back:

julia> using LinearAlgebra: dot

julia> 2 - dot([1 1], [1; 1]) == 0
true

or even just use vector multiplication:

julia> 2 - [1, 1]' * [1, 1] == 0
true
4 Likes

Good! I think this may be what I most want. Thanks a lot!

1 Like

Not that dot([1, 2], [3, 4]) and [1, 2]' * [3, 4] are essentially equivalent in Julia, because [1, 2]' acts like a covector, as discussed in Transposes vs 1-row matrices

3 Likes

Thanks! I see.

using LinearAlgebra: dot

a_vec = [1, 2] # 2-element Vector{Int64}
a_col_mat = [1; 2] # 2-element Vector{Int64}
a_row_mat = [1 2] # 1×2 Matrix{Int64}

a_vec == a_col_mat # true
a_vec != a_row_mat' # true
a_vec' * a_vec == a_col_mat' * a_vec # true
a_vec' * a_vec != a_row_mat * a_vec # true

a_vec' * a_vec == dot(a_vec, a_vec) # true
a_vec' * a_vec == dot(a_col_mat, a_vec) # true
a_vec' * a_vec == dot(a_row_mat, a_vec) # true

To make a 1-column matrix (2d array), you can use [1; 2;;]

1 Like

Thank you for making it more complete and accurate, although this kind of syntax makes me feel somewhat confused that I couldn’t find a consistent way to understand Julia’s syntax rules regarding vectors and matrices. :thinking:

It’s explained here in the manual:

Using double semicolons for the horizontal concatenation, on the other hand, performs any vertical concatenations before horizontally concatenating the result. […] Just as ; and ;; concatenate in the first and second dimension, using more semicolons extends this same general scheme. The number of semicolons in the separator specifies the particular dimension, so ;;; concatenates in the third dimension, ;;;; in the 4th, and so on. Fewer semicolons take precedence, so the lower dimensions are generally concatenated first.

(It’s not very common to need to define a 1-column matrix literal expression like [1; 2;;], and the syntax for this was only added to Julia fairly recently. I don’t think I’ve ever used it in practice myself. You can safely ignore the ;;… corner of the language if you find it confusing.)

3 Likes

Oh! Many many thanks! :handshake: :handshake:

Thank you so much, now I know that I can also define a matrix by columns in this way!

julia> [1;2;;3;4]
2×2 Matrix{Int64}:
 1  3
 2  4
1 Like

More strange things confused me: A column vector isn’t equal to a single-column matrix but a row vector is equal to a single-row matrix.

Why?

julia> col_vec = [1, 2]
2-element Vector{Int64}:
 1
 2

julia> row_vec = col_vec'
1×2 adjoint(::Vector{Int64}) with eltype Int64:
 1  2

julia> one_col_mat = [1; 2;;]
2×1 Matrix{Int64}:
 1
 2

julia> one_row_mat = [1 2]
1×2 Matrix{Int64}:
 1  2

julia> one_col_mat'
1×2 adjoint(::Matrix{Int64}) with eltype Int64:
 1  2

julia> one_row_mat'
2×1 adjoint(::Matrix{Int64}) with eltype Int64:
 1
 2

julia> col_vec == one_col_mat
false

julia> col_vec == one_row_mat'
false

julia> row_vec == one_col_mat'
true

julia> row_vec == one_row_mat
true

julia> one_col_mat == one_row_mat'
true

julia> one_row_mat == one_col_mat'
true

There is no such thing as a row-vector in julia. When you transpose or form the adjoint of a Vector you get a 2-dimensional structure, essentially a one-row matrix.

julia> a = rand(4)
4-element Vector{Float64}:
 0.2034574270239713
 0.7019936882200452
 0.9387129254650988
 0.5892713898810321

julia> b = a'
1×4 adjoint(::Vector{Float64}) with eltype Float64:
 0.203457  0.701994  0.938713  0.589271

julia> size(a)
(4,)

julia> size(b)
(1, 4)

But, I agree that it’s a bit confusing, because the adjoint acts as a co-vector, not as a 1x4 matrix when multiplying with a vector.

1 Like

But they have different types:

julia> typeof(row_vec)
LinearAlgebra.Adjoint{Int64, Vector{Int64}}

julia> typeof(one_row_mat)
Matrix{Int64} (alias for Array{Int64, 2})

julia> typeof(row_vec) == typeof(one_row_mat)
false

How can two instances from different types equal to each other? Given

The type system is more powerful than that. In general, comparing types with == is usually a bad idea. Use isa or <: instead.

In particular, relevant for this case:

julia> LinearAlgebra.Adjoint <: AbstractMatrix
true

julia> Matrix <: AbstractMatrix
true

BTW, asking questions here is completely fine, but TBH I think using the Manual more would be an efficiency win for you, given that I think all your questions are answered in the Manual.

BTW, in case you’re interested, the docs for <: are better in the in-development version of Julia than for the released version, here’s the link: <:

1 Like

Thanks!

Thank you for your advice! I completely agree and acknowledge that I need to improve my efficiency in accurately locating my issues in the documentation. It is undeniable that asking questions here has provided me with a lot of friendly help (including yours), which has increased my familiarity with the documentation and helped me learn things beyond the documentation. For example, I learned from you that

This information has been very helpful.

I apologize for the presumption, but I cannot agree with your viewpoint that seems too absolute. As a novice in the Julia language, although some of my questions may appear elementary to you, the fact is that through my interactions and discussions with the community here, as well as my own exploration, I have discovered several (potential) bugs in Julia itself or in Julia packages (perhaps more than five recently?) and raised some issues on GitHub. Don’t you think this is beneficial for Julia, its developers, and its users? If your answer is negative, I will try to minimize my exploration and inquiries regarding such issues.

3 Likes

Please continue asking questions, they are absolutely welcome. Each answer here (even if only pointing to the proper manual page) helps other users to find answers to similar questions.

6 Likes