Stream: helpdesk (published)

Topic: ✔ Massive delay for dict variable?


view this post on Zulip Nicolas Arnold (Feb 12 2024 at 20:49):

Hey there. Maybe this is obvious, but I'm having trouble with dicts and the time it takes.
For example, I have a function that takes a graph and vertex positions and calculates the line segments for edges. This takes only ~15μs. But for some reason, the line the assigns this to a dictionary takes like ~50ms, the line is edges_to_segments::Dict{Tuple{Graphs.SimpleGraphs.SimpleEdge{Int64}, Int64}, GeometryBasics.Line{2, Float32}} = get_edges_to_segments(G, positions)

Is there no way to use a dict and have this be fast? I tried giving a size hint and I don't think it did anything.

view this post on Zulip Gunnar Farnebäck (Feb 12 2024 at 21:48):

It's hard to even speculate without any information of what get_edges_to_segments actually does or how it is implemented.

view this post on Zulip Nicolas Arnold (Feb 12 2024 at 22:07):

Here is a minimum running example that is set up to demonstrates it.

using LinearAlgebra
using Graphs
using TimerOutputs
using GeometryBasics
using NetworkLayout




const to = TimerOutput()


function testing_generate_graph()
    n = rand(45:60)
    max_edges = n * (n - 1) ÷ 2
    e = min(3 * n - 4, max_edges)
    graph = SimpleGraph(n, e)
    #graph = SimpleDiGraph(n, e)
    return graph
end

function testing_generate_layout(graph::AbstractGraph)
    layout = SFDP(Ptype = Float32, tol = 0.01, C = 0.2, K = 1)
    #layout = Spring()
    positions = layout(graph)
    return positions
end



@timeit to function get_edges_to_segments(
    graph::AbstractGraph,
    positions::Vector{GeometryBasics.Point{2,Float32}},
)
    #=
    edges_to_segments = Dict(
        (e, i) => Segment(
            Meshes.Point(positions[src(e)][1], positions[src(e)][2]),
            Meshes.Point(positions[dst(e)][1], positions[dst(e)][2]),
        ) for (i, e) in enumerate(edges(graph))
    ) =#
    edges_to_segments::Dict{Tuple{Graphs.SimpleGraphs.SimpleEdge{Int64}, Int64}, GeometryBasics.Line{2, Float32}} = Dict(
        (e, i) => GeometryBasics.Line(
            positions[src(e)],
           positions[dst(e)],
        ) for (i, e) in enumerate(edges(graph))
    )

    return edges_to_segments
end


G = testing_generate_graph()
vertpositions = testing_generate_layout(G)





@timeit to "section1" begin
result = get_edges_to_segments(G, vertpositions)
end



to_flatten = TimerOutputs.flatten(to)
show(to_flatten; compact = true, allocations = false)

view this post on Zulip chriselrod (Feb 13 2024 at 07:36):

What if you define

    edges_to_segments::Dict{Tuple{Graphs.SimpleGraphs.SimpleEdge{Int64}, Int64}, GeometryBasics.Line{2, Float32}} = Dict{Tuple{Graphs.SimpleGraphs.SimpleEdge{Int64}, Int64}, GeometryBasics.Line{2, Float32}}(
        (e, i) => GeometryBasics.Line(
            positions[src(e)],
           positions[dst(e)],
        ) for (i, e) in enumerate(edges(graph))
    )

?
That is, create your initial dict with the desired type, rather than with ??? type and converting it to the desired type.

view this post on Zulip jar (Feb 13 2024 at 07:39):

I think this was solved on Discourse

view this post on Zulip Notification Bot (Feb 20 2024 at 19:03):

Lilith Hafner has marked this topic as resolved.


Last updated: Dec 28 2024 at 04:38 UTC