Looping in Julia

I have written the code displayed below to calculate the maximum distance which is working perfectly. I want to modify the code for another task but facing some challenges. I will be grateful for any help and guidance please. This is what I want to do:
I want to calculate the distance from each center (xs,ys) to all points (a,b). Thus if center is (0,0) I need the distance from this center to all points in (a,b). I also want to create a matrix such that if the distance between a center to the various points is less than or equal to 2(<=2), it should write one in the matrix but if its greater than 2 it should write zero in the matrix. This process should happen from each of the centers (xs,ys) to all points in (a,b) for me to get a matrix with ones and zeros after calculating the distance from each center to all points . I am particularly interested in displaying the matrix with ones and zeros after each iteration. I will be very grateful for help to get this done please. Thank you for helping me. Below is my code which I want to modify to accomplish this task.


xs=[0 2.5 -2.5 2 -2.5 -3 -4 1.5 -1 3.7] #x-cordinates of center
ys=[0 0.3 0.25 -2.5 -2.25 1.5 -1.7 2 -3 -2]# y-cordinates of center

a=[-1, -1, 1.2, 1.2, 1.2, 0.8, 2.5, 2.5, -3, -3, -1.5, 3, 0.9, -3.7, 3.7, 3, 1.8, -1.8, -3.7, -3.7, 0.5, 2.5, -2.2, 3.5, 0.5 ] #x cordinate of the points
b=[0.2, 0.8, -0.85, 1.2, 0.5, -1.5, -1.3, 1.4, 1.5, -1.3, -0.8, -2.7, -2.4, 0.5, 0.8, 2.8, 2.4, -2.6, -2.6, 2.6, 1.5, -2.5, -3.3, -0.8, 3.1 ] #y cordinate of the points
r=[]  

function distance(xs, ys, a, b) 
    r = Float64[]
    for (i,xv) in enumerate(xs)
        R = Float64[]
        for (j, jv) in enumerate(a)
           
                push!(R, ((xs[i]-a[j])^2 + (ys[i]-b[j])^2)^0.5)
        
         end
         if length(R) > 0
             push!(r, maximum(R))
         end
    end
    return r
end
r=distance(xs, ys, a, b)

How about Distances.pairwise?

using Distances

xs=[0 2.5 -2.5 2 -2.5 -3 -4 1.5 -1 3.7] #x-cordinates of center
ys=[0 0.3 0.25 -2.5 -2.25 1.5 -1.7 2 -3 -2]# y-cordinates of center

a=[-1, -1, 1.2, 1.2, 1.2, 0.8, 2.5, 2.5, -3, -3, -1.5, 3, 0.9, -3.7, 3.7, 3, 1.8, -1.8, -3.7, -3.7, 0.5, 2.5, -2.2, 3.5, 0.5 ] #x cordinate of the points
b=[0.2, 0.8, -0.85, 1.2, 0.5, -1.5, -1.3, 1.4, 1.5, -1.3, -0.8, -2.7, -2.4, 0.5, 0.8, 2.8, 2.4, -2.6, -2.6, 2.6, 1.5, -2.5, -3.3, -0.8, 3.1 ] #y cordinate of the points

xy = [xs ; ys]
ab = [a' ; b']
pairwise(Euclidean(), xy, ab)
maximum(pairwise(Euclidean(), xy, ab))
julia> xy = [xs ; ys]
2×10 Matrix{Float64}:
 0.0  2.5  -2.5    2.0  …  1.5  -1.0   3.7   
 0.0  0.3   0.25  -2.5     2.0  -3.0  -2.0   

julia> ab = [a' ; b']
2×25 Matrix{Float64}:
 -1.0  -1.0   1.2   …  -2.2   3.5  0.5       
  0.2   0.8  -0.85     -3.3  -0.8  3.1       

julia> pairwise(Euclidean(), xy, ab)
10×25 Matrix{Float64}:
 1.0198   1.28062  …  3.59026  3.14006       
 3.50143  3.53553     1.48661  3.44093       
 1.50083  1.59765     6.09118  4.13793       
 4.03609  4.45982     2.26716  5.79741       
 2.87272  3.3989      6.17272  6.13372       
 2.38537  2.11896  …  6.89493  3.84838       
 3.55106  3.90512     7.55381  6.57951       
 3.08058  2.77308     3.44093  1.48661       
 3.2      3.8         5.00899  6.28172       
 5.18941  5.47083     1.21655  6.0208        

julia> maximum(pairwise(Euclidean(), xy, ab))
8.713208364316786

For reprod your result, dims = 2 is included.

julia> maximum(pairwise(Euclidean(), xy, ab), dims = 2) # my code
10×1 Matrix{Float64}:
 4.522167621838006
 6.844705983459042
 6.241193796061776
 7.648529270389178
 7.466759672039807
 7.323933369440222
 8.32165848854662
 6.942621983083913
 7.045565981523415
 8.713208364316786

julia> r=distance(xs, ys, a, b) # your code
10-element Vector{Float64}:
 4.522167621838006
 6.844705983459042
 6.241193796061776
 7.648529270389178
 7.466759672039807
 7.323933369440222
 8.32165848854662
 6.942621983083913
 7.045565981523415
 8.713208364316786
1 Like

There are many ways to answer the question. I will give you one answer which is very close to your approach. Just to avoid over-optimisation and making it complicated.

The new aspect here is that while for vectors you can use push!, for matices you need
to create a matrix with the correct size from the beginning!
In general, it is always a good idea to initialise your arrays directly with the size they need.

function distance(xs, ys, a, b) 
    n = length(xs)
    m = length(a)
    r = zeros(n, m)  # create the matrix and fill it with zeros
    for j in 1:m
        for i in 1:n
            if sqrt( (xs[i]-a[j])^2 + (ys[i]-b[j])^2 ) < 2 
                r[i,j] = 1
                @show i j r      # display the matrix in each iteration
            end
         end
    end
    return r
end

Now, there are many ways how to make it faster and more elegant,
for example as @rmsmsgood showed you!

Here’s an approach built on broadcasting. It will return a logical array, a BitMatrix, instead of a Matrix{Float64}, which may make sense, or not be quite what you are looking for:

r = @. sqrt((xs - a)^2 + (ys - b)^2) < 2

The @. is a macro which puts broadcasting dots in all the right places. It’s the same as writing:

r = sqrt.((xs .- a).^2 .+ (ys .- b).^2) .< 2

If you would rather prefer a Matrix{Bool} or a Matrix{Float64}, etc., you can just pre-allocate r and then move the @. in front of the entire expression:

r = Matrix{Bool}(undef, length(a), length(xs))  # or Matrix{Float64}(...)
@. r = sqrt((xs - a)^2 + (ys - b)^2) < 2

which is the same as

r = Matrix{Bool}(undef, length(a), length(xs))
r .= sqrt.((xs .- a).^2 .+ (ys .- b).^2) .< 2

Broadcasting can really simplify some awkward expressions.

A couple of remarks on your code:

If you know the size of the array beforehand, it is much more efficient to pre-allocate it and then fill it, than to initialize an empty vector and push!ing repeatedly.

You should normally use sqrt(x) instead of x^0.5. I’m unsure if there are differences in accuracy, but sqrt is much, much faster.

When I run this code I get the error “distance (generic function with 2 methods)”

How do I make this work, please?

I just called the function and its working now. Thank you

@rmsmsgood .
This method is not giving me the expected results, please. I actually want to display a matrix with ones and zeros as I gave the conditions in my question. Thank you for you guidance. I have learnt a lot with the help. The code from @ SteffenPL gives an expected results. Highly appreciated please. Thank you