"""
    function recallfull(ranks::AbstractArray, rtrue::AbstractArray)

Computes the relative number of matches in the input ranking with respect to the input ground truth
"""
function recallfull(ranks::AbstractArray, rtrue::AbstractArray)
    recall = 0
    nn, m = size(rtrue)
    @assert size(ranks)[1] == size(rtrue)[1]
    for i in 1:m
        recall += size(findall(in(ranks[:,i]),rtrue[:,i]))[1]        
    end
    return recall / (nn*m)
end

"""
    recallN(ranks::AbstractArray, rtrue::AbstractArray, N)

Takes a parameter `N` and computes the N@N recall between the input ranking and the input ground truth.
"""
function recallN(ranks::AbstractArray, rtrue::AbstractArray, N)
    recall = 0
    nn, m = size(rtrue)
    for i in 1:m
        recall += size(findall(in(ranks[1:N,i]),rtrue[1:N,i]))[1]        
    end
    return recall / (N*m)
end

"""
    recallN(ranks::AbstractArray, rtrue::AbstractArray, N)

Takes a parameter `N` and computes the 1@N recall between the input ranking and the input ground truth.
"""
function recall1atN(ranking::AbstractArray, rtrue::AbstractArray,N)
    score = 0
    n_queries = length(rtrue[1,:])
    for i in 1:n_queries
        if rtrue[1,i] in @view(ranking[1:N,i])
            score+=1
        end
    end
    return score / n_queries
end

"""
    approx_error(qd::QuantizerData, data::AbstractMatrix, rtrue::AbstractArray, queries::AbstractArray)

Takes the input approximation data generated by a constructor, the exact data set, the true nearest neighbors and a set of test queries.
Takes the nearest neighbor to each query, computes the approximated inner product with the query and the true inner product with the query
Returns the average normalized absolute between the two: `|<q, ̃x-x>-<q,x>|`
"""
function approx_error(qd::QuantizerData, data::AbstractMatrix, rtrue::AbstractArray, queries::AbstractArray)
    dist = zeros(size(queries)[2])
    for i in 1:size(queries)[2]
        qTx = dot(queries[:,i], data[:,rtrue[1,i]])
        qTx_approx = dot(queries[:,i], qd.I.B[rtrue[1,i]]'qd.C)
        dist[i] = abs((qTx - qTx_approx)/qTx)
    end
    return mean(dist)
end

"""
    function get1atNscores(yhat::AbstractMatrix, groundtruth::AbstractMatrix, n_neighbors::Int)

Computes the recall1atN score for every value between 1 and the input `n_neighbors` for the estimated
ranking and the groundtruth and outputs as a vector. Used for creating comparative 1@N plots.
"""
function get1atNscores(yhat::AbstractMatrix, groundtruth::AbstractMatrix, n_neighbors::Int)
    scores = zeros(n_neighbors)
    for i in 1:n_neighbors
        scores[i] = recall1atN(yhat, groundtruth, i)
    end
    return scores
end

export recallfull
export recallN
export recall1atN
export approx_error
export get1atNscores