2
\$\begingroup\$

I have a simple brute-force search function:

function run_query(search_data::Vector{Float64}, query::Vector{Float64}, search_f::Function)::Tuple{Float64, Int}
    current_best = Inf
    loc = -1
    q_len = length(query)

    for d_i in 1:(length(data) - q_len)

        dist = search_f(data[d_i:d_i+q_len-1], query)
        if dist < current_best
            current_best = dist
            loc = d_i
        end
    end

    return current_best, loc
end

I have an alternative version of the function which also returns the maximum distance found while searching to data:

function run_query_max(search_data::Vector{Float64}, query::Vector{Float64}, search_f::Function)::Tuple{Float64, Int, Float64}
    current_best = Inf
    loc = -1
    q_len = length(query)
    max_dist = 0.

    for d_i in 1:(length(data) - q_len)

        dist = search_f(data[d_i:d_i+q_len-1], query)

        if dist > max_dist
            max_dist = dist
        end

        if dist < current_best
            current_best = dist
            loc = d_i
        end
    end

    return current_best, loc, max_dist
end

This can be tested as follows:

function simple_dist(data::Vector{Float64}, query::Vector{Float64})::Float64
    return sum((data .- query) .^ 2)
end

data = [0., 0., 1., 2.,
        3., 1.1, 3., 3.,
        1., 0., 0., 1.,
        0., 0., 1., 4.5,
        2., 1., 0., 0.]

query = [1., 2., 3., 1.]
val, idx = run_query(data, query, simple_dist)
@assert (idx == 3)
@assert isapprox(val, 0.01, atol=0.001)

val, idx, max_dist = run_query_max(data, query, simple_dist)
@assert (idx == 3)
@assert isapprox(val, 0.01, atol=0.001)
@assert isapprox(max_dist, 21.25, atol=0.001)

This pattern of:

  1. Basic search function
  2. Add keeping track of maximum distance in search function

Occurs in multiple places in my code. What is a reasonable way to refactor it out?

\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

I think this depends a lot on your motivation for separating these into two methods.

One simple option I would consider first is to just have 1 version of each of these functions to avoid the duplication in the first place. The caller can just ignore the max_dist value if they don't need it.

If performance is an issue and max_distcalculation could be a bottleneck, you could add a Boolean argument to the single function to indicate if max_dist should be calculated or not.

If the logic for max_dist is complex enough to hurt the readability of the basic search, I think you may be better off going with the duplication instead of doing something more complex. It could be done, but not in a way I would consider reasonable in most cases.

\$\endgroup\$
1
  • \$\begingroup\$ Yeah, I'm also considering I might need to do benchmarking to guide whether I should worry about this or not. \$\endgroup\$
    – Seanny123
    Commented Jan 30, 2019 at 14:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.