LoadError: MethodError: no method matching

Hello,

Given two distinct points Start =[xS,yS] and End = [xE,yE] in 2d, my aim is to find a simple way to generate N evenly-spaced points along the shortest path between Start and End.
That is, I want a generalization of something like LinRange(xS, xE, N)

Pseudocode

Input:  Start = [xS, yS]
        End = [xE, yE]
        N 

Output: Path = [xS,yS; ... ; xE,yE] with len(Path) = N

# vertical line
if xE-xS == 0 && |yE-yS| > 0 	
	yPts = LinRange(yS, yE, N)
	for i in 1:N
		Path = [xS, yPts[i]]
	end
# horizontal line
elseif |xE-xS| > 0 && yE-yS == 0 	
	xPts = LinRange(xS, xE, N)
	for i in 1:N
		Path = [xPts[i], yS]
	end	
# sloped line: y[i] = m x[i] + b
elseif |xE-xS| > 0 &&  |yE-yS| > 0 	
	slope = (yE-yS)/(xE-xS)
	b = yS - slope*xS
	xPts = LinRange(xS, xE, N)
	for i in 1:N
		Path = [xPts[i], slope*xPts[i]+b ]
	end	
elseif
	println("Start and end point are the same")
end

Attempt

function find_2dPath(Start::Matrix{Float64}, End::Matrix{Float64}, N::Int)
    xS = Start[1]
    yS = Start[2]
    xE = End[1]
    yE = End[2]

    Path = Matrix{Float64}(undef,N,2)
    #@show Path
    #println("Type of 'Path' = ", typeof(Path))
    
    if xE-xS == 0 && abs(yE-yS) > 0 	#vertical line
    	yPts = LinRange(yS, yE, N)
    	for i in 1:N
            	newPt = convert(Matrix{Float64,1}, [xS, yPts[i]] )
    		Path = push!(Path, newPt)
    	end
    elseif abs(xE-xS) > 0 && yE-yS == 0 	#horizontal line
    	xPts = LinRange(xS, xE, N)
    	for i in 1:N
            	newPt = convert(Matrix{Float64,1}, [xPts[i], yS] )
    		Path = push!(Path, newPt)
    	end	
    elseif abs(xE-xS) > 0 &&  abs(yE-yS) > 0 	#sloped line
    	slope = (yE-yS)/(xE-xS)
    	b = yS - slope*xS
    	xPts = LinRange(xS, xE, N)
    	for i in 1:N
            	ypt = slope*xPts[i] + b    #y = mx+b
            	# newPt = convert(Array{Float64,1}, [xPts[i], ypt] )
            	# newPt = reshape([xPts[i], ypt], 2, 1)
                newPt = 	reshape(	reduce(vcat,transpose.([xPts[i], ypt])) ,  2, 1)
    		Path =  push!(Path, newPt ) 
    	end	
    end
    return Path
end


let 
    ## Example 1: Path = 10 points between (0,0) -> (1,1) 
    Start1 = [0.0, 0.0]
    End1 = [1.0, 1.0]
    N1 = 10
    
    path1 = find_2dPath(Start1,End1, N1)
    @show path1
end

Generic error message

ERROR: LoadError: MethodError: no method matching find_2dPath(::Vector{Float64}, ::Vector{Float64}, ::Int64)
Closest candidates are:
  find_2dPath(::Matrix{Float64}, ::Matrix{Float64}, ::Int64) at
  ...

Any help you can give me in understanding or resolving this error message is greatly appreciated!

Start1 is a Vector while your function expects a Matrix

Start1 = [0.0 0.0] (no comma) generates a Matrix. But you probably want to pass either a Vector or a Tuple to find2dPath.

1 Like

I think the error message is quite good in this case, so you are constraining the argument types to be matrices:

find_2dPath(Start::Matrix{Float64}, End::Matrix{Float64}, N::Int)

But you are calling it with Vectors, which are not the same:

julia> typeof([0.0, 0.0])
Vector{Float64} (alias for Array{Float64, 1})

So the error message is telling you that you are trying to call a method that does not exist.

Apart from what @hendri54 says, you may want to remove the constraint on the types from the definition of the function.

1 Like

Thank you to @hendri54 and @aramirezreyes !

For those interested here’s the updated version of my code where
(1) I removed the Matrix constraint in the function-input,
(2) I changed the data type from {Float64} to Any
(3) Added some lines to investigate the array-of-tuples output

function find_2dPath(Start, End, N)
    xS = Start[1]
    yS = Start[2]
    xE = End[1]
    yE = End[2]

    Path = Any[] #Array{Float64}(undef,N,2)
    #@show Path
    #println("Type of 'Path' = ", typeof(Path))
    	
    if xE-xS == 0 && abs(yE-yS) > 0 	#vertical line
    	yPts = LinRange(yS, yE, N)
    	for i in 1:N
    		push!(Path, (xS, yPts[i]))
    	end
    elseif abs(xE-xS) > 0 && yE-yS == 0 	#horizontal line
    	xPts = LinRange(xS, xE, N)
    	for i in 1:N
    		push!(Path, (xPts[i], yS))
    	end	
    elseif abs(xE-xS) > 0 &&  abs(yE-yS) > 0 	#sloped line
    	slope = (yE-yS)/(xE-xS)
    	b = yS - slope*xS
    	xPts = LinRange(xS, xE, N)
    	for i in 1:N
            	yPt = slope*xPts[i] + b    #y = mx+b
            	push!(Path, (xPts[i], yPt))
    	end	
    end 
    return Path
    # This gives an array of tuples Any[(x1,y1), (x2,y2), ... (xN, yN)]
end


let 
    ## Example 1: path1 = 11 points between (0,0) -> (1,1) 
    Start1 = (0.0, 0.0)
    End1 = (1.0, 1.0)
    N1 = 11
    
    println("start = ", Start1)
    println("end = ", End1)
    println("N pts = ", N1)
    
    path1 = find_2dPath(Start1,End1, N1)
    @show path1
    println("Type of 'path1' = ", typeof(path1))
    println()
    
    println("'path1[2]' =",path1[2] )
    println("Type of 'path1[2]' = ", typeof(path1[2]))
    println()
    
    p1 = collect(path1[2]) 
    @show p1
    println("Type of 'p1' = ", typeof(p1))

end

BTW, isn’t that the same as

[(x,y)  for (x,y) in zip(LinRange(x1,x2,N), LinRange(y1,y2,N))]
2 Likes

@hendri54 Yes, it’s the same thing. I’m just new to Julia and its Python like qualities.