From ef7330254c191943552a4902b8c84bf5804ac356 Mon Sep 17 00:00:00 2001 From: David Einstein Date: Tue, 27 May 2014 23:44:57 -0400 Subject: [PATCH 01/13] Added vertex property inspectors. Currently, a-star search is the only algorithm using any vertex properties (for the distance heuristic), so the a-star code was changed. The a-star code used the vertex type to index into the colormap, so would only work with graphs with integer vertex type. I generalized and abstracted away the colormap type. This probably should be a separate commit. --- doc/source/vertex_edge.rst | 44 +++++++++++++++++++++++ src/Graphs.jl | 7 ++++ src/a_star_spath.jl | 27 +++++++++------ src/common.jl | 71 ++++++++++++++++++++++++++++++++++++-- test/a_star_spath.jl | 11 ++++++ 5 files changed, 148 insertions(+), 12 deletions(-) diff --git a/doc/source/vertex_edge.rst b/doc/source/vertex_edge.rst index c0078c1e..ff699854 100644 --- a/doc/source/vertex_edge.rst +++ b/doc/source/vertex_edge.rst @@ -101,6 +101,50 @@ Both edge types implement the following methods: A custom edge type ``E{V}`` which is constructible by ``E(index::Int, s::V, t::V)`` and implements the above methods is usable in the ``VectorIncidenceList`` parametric type. Construct such a list with ``inclist(V,E{V})``, where E and V are your vertex and edge types. See test/inclist.jl for an example. +Vertex Properties +--------------- + +Many algorithms use a property of an vertex such as amount of a +resource provided or required by that vertex as input. As the +algorithms do not mandate any structure for the vertex types, these +vertex properties can be passed through to the algorithm by an +``VertexPropertyInspector``. An ``VertexPropertyInspector`` when +passed to the ``vertex_property`` method along with an vertex and a +graph, will return that property of an vertex. + +All vertex property inspectors should be declared as a subtype of +``AbstractVertexPropertyInspector{T}`` where ``T`` is the type of the +vertex property. The vertex propery inspector should respond to the +following methods. + +.. py::function:: vertex_property(i, e, g) + + returns the vertex property of vertex ``v`` in graph ``g`` selected by + inspector ``i``. + +.. py::function:: vertex_property_requirement(i, g) + + checks that graph ``g`` implements the interface(s) necessary for + inspector ``i`` + +Three vertex property inspectors are provided +``ConstantVertexPropertyInspector``, ``VectorVertexPropertyInspector`` and +``AttributeVertexPropertyInspector``. + +``ConstantVertexPropertyInspector(c)`` constructs an vertex property +inspector that returns the constant ``c`` for each vertex. + +``VectorVertexPropertyInspector(vec)`` constructs an vertex property +inspector that returns ``vec[vertex_index(v, g)]``. It requires that +``g`` implement the ``vertex_map`` interface. + +``FunctionVertexPropertyInspector(func)`` constructs an vertex property +inspector that returns the result of ``func(v)`` from an ``ExVertex``. +``AttributeVertexPropertyInspector`` requires that the graph implements +the ``vertex_map`` interface. + + + Edge Properties --------------- diff --git a/src/Graphs.jl b/src/Graphs.jl index 3be685ff..f8550519 100644 --- a/src/Graphs.jl +++ b/src/Graphs.jl @@ -37,6 +37,13 @@ module Graphs ConstantEdgePropertyInspector, AttributeEdgePropertyInspector, edge_property, edge_property_requirement, + AbstractVertexPropertyInspector, ConstantVertexPropertyInspector, + FunctionVertexPropertyInspector, VectorVertexPropertyInspector, + vertex_property_requirement, vertex_property, + + AbstractVertexColormap, VectorVertexColormap, HashVertexColormap, + vertex_colormap_requirement, setindex!, getindex, + # edge_list GenericEdgeList, EdgeList, simple_edgelist, edgelist, diff --git a/src/a_star_spath.jl b/src/a_star_spath.jl index 2ce36c19..9e5d9654 100644 --- a/src/a_star_spath.jl +++ b/src/a_star_spath.jl @@ -20,9 +20,9 @@ export shortest_path function a_star_impl!{V,D}( graph::AbstractGraph{V},# the graph frontier, # an initialized heap containing the active vertices - colormap::Vector{Int}, # an (initialized) color-map to indicate status of vertices + colormap::AbstractVertexColormap{Int}, # an (initialized) color-map to indicate status of vertices edge_dists::AbstractEdgePropertyInspector{D}, # cost of each edge - heuristic::Function, # heuristic fn (under)estimating distance to target + heuristic::AbstractVertexPropertyInspector{Int}, # heuristic fn (under)estimating distance to target t::V) # the end vertex while !isempty(frontier) @@ -33,16 +33,16 @@ function a_star_impl!{V,D}( for edge in out_edges(u, graph) v = target(edge) - if colormap[v] < 2 - colormap[v] = 1 + if colormap[v,graph] < 2 + colormap[v,graph] = 1 new_path = cat(1, path, edge) path_cost = cost_so_far + edge_property(edge_dists, edge, graph) enqueue!(frontier, (path_cost, new_path, v), - path_cost + heuristic(v)) + path_cost + vertex_property(heuristic,v, graph)) end end - colormap[u] = 2 + colormap[u,graph] = 2 end nothing end @@ -53,12 +53,17 @@ function shortest_path{V,E,D}( edge_dists::AbstractEdgePropertyInspector{D}, # cost of each edge s::V, # the start vertex t::V, # the end vertex - heuristic::Function = n -> 0) + heuristic::AbstractVertexPropertyInspector{Int} = ConstantVertexPropertyInspector(0)) + # heuristic (under)estimating distance to target frontier = PriorityQueue{(D,Array{E,1},V),D}() frontier[(zero(D), E[], s)] = zero(D) - colormap = zeros(Int, num_vertices(graph)) - colormap[s] = 1 + if implements_vertex_map(graph) + colormap = VectorVertexColormap{Int}(zeros(Int, num_vertices(graph))) + else + colormap = HashVertexColormap{Int}(Dict{V,Int}()) + end + colormap[s,graph] = 1 a_star_impl!(graph, frontier, colormap, edge_dists, heuristic, t) end @@ -67,8 +72,10 @@ function shortest_path{V,E,D}( edge_dists::Vector{D}, # cost of each edge s::V, # the start vertex t::V, # the end vertex - heuristic::Function = n -> 0) + fheuristic::Function = n -> 0) edge_len::AbstractEdgePropertyInspector{D} = VectorEdgePropertyInspector(edge_dists) + + heuristic = FunctionVertexPropertyInspector{Int}(fheuristic) shortest_path(graph, edge_len, s, t, heuristic) end diff --git a/src/common.jl b/src/common.jl index fa73e25c..08c4ed2b 100644 --- a/src/common.jl +++ b/src/common.jl @@ -143,7 +143,39 @@ next(a::SourceIterator, s::Int) = ((e, s) = next(a.lst, s); (source(e, a.g), s)) ################################################# # -# Edge Length Visitors +# Vertex Property Inspectors +# +################################################ + +abstract AbstractVertexPropertyInspector{T} + +vertex_property_requirement{T, V}(visitor::AbstractVertexPropertyInspector{T}, g::AbstractGraph{V}) = nothing + +type ConstantVertexPropertyInspector{T} <: AbstractVertexPropertyInspector{T} + value::T +end + +vertex_property{T}(visitor::ConstantVertexPropertyInspector{T}, v, g) = visitor.value + +type VectorVertexPropertyInspector{T} <: AbstractVertexPropertyInspector{T} + values::Vector{T} +end + +vertex_property{T,V}(visitor::VectorVertexPropertyInspector{T}, v::V, + g::AbstractGraph{V})= visitor.values[vertex_index(v,g)] + +vertex_property_requirement{T, V}(visitor::VectorVertexPropertyInspector{T}, g::AbstractGraph{V}) = @graph_requires g vertex_map + + +type FunctionVertexPropertyInspector{T} <: AbstractVertexPropertyInspector{T} + f::Function +end + +vertex_property{T}(visitor::FunctionVertexPropertyInspector{T}, v, g) = visitor.f(v) + +################################################# +# +# Edge Property Inspectors # ################################################ @@ -164,7 +196,7 @@ end edge_property{T,V}(visitor::VectorEdgePropertyInspector{T}, e, g::AbstractGraph{V}) = visitor.values[edge_index(e, g)] -edge_property_requirement{T, V}(visitor::AbstractEdgePropertyInspector{T}, g::AbstractGraph{V}) = @graph_requires g edge_map +edge_property_requirement{T, V}(visitor::VectorEdgePropertyInspector{T}, g::AbstractGraph{V}) = @graph_requires g edge_map type AttributeEdgePropertyInspector{T} <: AbstractEdgePropertyInspector{T} attribute::UTF8String @@ -173,6 +205,41 @@ end function edge_property{T}(visitor::AttributeEdgePropertyInspector{T},edge::ExEdge, g) convert(T,edge.attributes[visitor.attribute]) end + +################################################# +# +# vertex colormap +# +################################################ + +abstract AbstractVertexColormap{T} + +vertex_colormap_requirement{T, V}(color::AbstractVertexColormap{T}, + g::AbstractGraph{V}) = nothing + +type VectorVertexColormap{T} <: AbstractVertexColormap{T} + values::Vector{T} +end + +vertex_colormap_requirement{T, V}(color::VectorVertexColormap{T}, + g::AbstractGraph{V}) = @graph_requires g vertex_map + +getindex{T,V}(color::VectorVertexColormap{T}, + v::V, g::AbstractGraph{V}) = color.values[vertex_index(v,g)] + +setindex!{T,V}(color::VectorVertexColormap{T}, x::T, + v::V, g::AbstractGraph{V}) = color.values[vertex_index(v,g)]=x + +type HashVertexColormap{T, V} <: AbstractVertexColormap{T} + values::Dict{V,T} +end + +getindex{T,V}(color::HashVertexColormap{T}, + v::V, g::AbstractGraph{V}) = color.values[v,g] + +setindex!{T,V}(color::HashVertexColormap{T}, x::T, + v::V, g::AbstractGraph{V}) = color.values[v]=x + ################################################# # # convenient functions diff --git a/test/a_star_spath.jl b/test/a_star_spath.jl index 33394663..c230bb00 100644 --- a/test/a_star_spath.jl +++ b/test/a_star_spath.jl @@ -46,3 +46,14 @@ end sp = shortest_path(g1, eweights1, 1, 2, n -> g1_heuristics[n]) edge_numbers = map(e -> edge_index(e, g1), sp) @test edge_numbers == [2, 7, 15, 16] + +g2 = inclist(KeyVertex{Char}) +vs = [add_vertex!(g2, 'a'+i) for i = 0:19] +for i = 1 : ne + we = g1_wedges[i] + add_edge!(g2, vs[we[1]], vs[we[2]]) +end + +sp2 = shortest_path(g2, VectorEdgePropertyInspector(eweights1), vs[1], vs[2], + VectorVertexPropertyInspector(g1_heuristics)) +@test map(e -> edge_index(e, g2), sp2) == [2, 7, 15, 16] From 9f41e05c8a8c2f5932c2a740ed096da845abd5dd Mon Sep 17 00:00:00 2001 From: David Einstein Date: Wed, 28 May 2014 08:36:23 -0400 Subject: [PATCH 02/13] Fixed typing of heuristic inspector --- src/a_star_spath.jl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/a_star_spath.jl b/src/a_star_spath.jl index 9e5d9654..03f45163 100644 --- a/src/a_star_spath.jl +++ b/src/a_star_spath.jl @@ -17,12 +17,12 @@ using Base.Collections export shortest_path -function a_star_impl!{V,D}( +function a_star_impl!{V,D,DH}( graph::AbstractGraph{V},# the graph frontier, # an initialized heap containing the active vertices colormap::AbstractVertexColormap{Int}, # an (initialized) color-map to indicate status of vertices edge_dists::AbstractEdgePropertyInspector{D}, # cost of each edge - heuristic::AbstractVertexPropertyInspector{Int}, # heuristic fn (under)estimating distance to target + heuristic::AbstractVertexPropertyInspector{DH}, # heuristic fn (under)estimating distance to target t::V) # the end vertex while !isempty(frontier) @@ -48,12 +48,12 @@ function a_star_impl!{V,D}( end -function shortest_path{V,E,D}( +function shortest_path{V,E,D,DH}( graph::AbstractGraph{V,E}, # the graph edge_dists::AbstractEdgePropertyInspector{D}, # cost of each edge s::V, # the start vertex t::V, # the end vertex - heuristic::AbstractVertexPropertyInspector{Int} = ConstantVertexPropertyInspector(0)) + heuristic::AbstractVertexPropertyInspector{DH} = ConstantVertexPropertyInspector(0)) # heuristic (under)estimating distance to target frontier = PriorityQueue{(D,Array{E,1},V),D}() @@ -75,7 +75,7 @@ function shortest_path{V,E,D}( fheuristic::Function = n -> 0) edge_len::AbstractEdgePropertyInspector{D} = VectorEdgePropertyInspector(edge_dists) - heuristic = FunctionVertexPropertyInspector{Int}(fheuristic) + heuristic = FunctionVertexPropertyInspector{D}(fheuristic) shortest_path(graph, edge_len, s, t, heuristic) end From 7a3dd169c0223cd16672b9ff7dd2422eadd80c52 Mon Sep 17 00:00:00 2001 From: David Einstein Date: Wed, 28 May 2014 08:41:09 -0400 Subject: [PATCH 03/13] Fixed cut/paste induced grammar error --- doc/source/vertex_edge.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/source/vertex_edge.rst b/doc/source/vertex_edge.rst index ff699854..420b66e7 100644 --- a/doc/source/vertex_edge.rst +++ b/doc/source/vertex_edge.rst @@ -104,13 +104,13 @@ A custom edge type ``E{V}`` which is constructible by ``E(index::Int, s::V, t::V Vertex Properties --------------- -Many algorithms use a property of an vertex such as amount of a +Many algorithms use a property of a vertex such as amount of a resource provided or required by that vertex as input. As the algorithms do not mandate any structure for the vertex types, these vertex properties can be passed through to the algorithm by an ``VertexPropertyInspector``. An ``VertexPropertyInspector`` when -passed to the ``vertex_property`` method along with an vertex and a -graph, will return that property of an vertex. +passed to the ``vertex_property`` method along with a vertex and a +graph, will return that property of a vertex. All vertex property inspectors should be declared as a subtype of ``AbstractVertexPropertyInspector{T}`` where ``T`` is the type of the @@ -131,14 +131,14 @@ Three vertex property inspectors are provided ``ConstantVertexPropertyInspector``, ``VectorVertexPropertyInspector`` and ``AttributeVertexPropertyInspector``. -``ConstantVertexPropertyInspector(c)`` constructs an vertex property +``ConstantVertexPropertyInspector(c)`` constructs a vertex property inspector that returns the constant ``c`` for each vertex. -``VectorVertexPropertyInspector(vec)`` constructs an vertex property +``VectorVertexPropertyInspector(vec)`` constructs a vertex property inspector that returns ``vec[vertex_index(v, g)]``. It requires that ``g`` implement the ``vertex_map`` interface. -``FunctionVertexPropertyInspector(func)`` constructs an vertex property +``FunctionVertexPropertyInspector(func)`` constructs a vertex property inspector that returns the result of ``func(v)`` from an ``ExVertex``. ``AttributeVertexPropertyInspector`` requires that the graph implements the ``vertex_map`` interface. From 53044550d22d59c26e0506db93ce98215f02d68b Mon Sep 17 00:00:00 2001 From: David Einstein Date: Wed, 28 May 2014 15:25:58 -0400 Subject: [PATCH 04/13] interim checkin --- src/a_star_spath.jl | 2 +- src/hashgraph.jl | 72 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 src/hashgraph.jl diff --git a/src/a_star_spath.jl b/src/a_star_spath.jl index 03f45163..da546f9b 100644 --- a/src/a_star_spath.jl +++ b/src/a_star_spath.jl @@ -61,7 +61,7 @@ function shortest_path{V,E,D,DH}( if implements_vertex_map(graph) colormap = VectorVertexColormap{Int}(zeros(Int, num_vertices(graph))) else - colormap = HashVertexColormap{Int}(Dict{V,Int}()) + colormap = HashVertexColormap{Int}(DefaultDict{V,Int}(0)) end colormap[s,graph] = 1 a_star_impl!(graph, frontier, colormap, edge_dists, heuristic, t) diff --git a/src/hashgraph.jl b/src/hashgraph.jl new file mode 100644 index 00000000..98eedba9 --- /dev/null +++ b/src/hashgraph.jl @@ -0,0 +1,72 @@ +type HashUndirectedGraph{V,E} <: AbstractGraph{V,E} + adj::Dict{V,Dict{V, E}} # u -> v -> edge(u,v) + edges::Dict{E,(V,V)} # edge -> (source, target) +} + +@graph_implements HashUndirectedGraph vertex_list edge_list +@graph_implements HashUndirectedGraph bidirectional_adjacency_list bidirectional_incidence_list + +source{V,E}(e::E, g::HashUndirectedGraph{V,E}) = g.edges[e][1] +target{V,E}(e::E, g::HashUndirectedGraph{V,E}) = g.edges[e][2] + + +is_directed(g::HashUndirectedGraph) = false + +num_vertices(g::HashUndirectedGraph) = length(g.adj) +vertices(g::HashUndirectedGraph) = keys(g.adj) + +num_edges(g::HashUndirectedGraph) = length(g.edges) +edges(g::HashUndirectedGraph) = keys(g.edges) + +out_edges{V}(v::V, g::HashUndirectedGraph{V}) = values(g.adj[v]) +out_degree{V}(v::V, g::HashUndirectedGraph{V}) = length(g.adj[v]) +out_neighbors{V}(v::V, g::HashUndirectedGraph{V}) = keys(g.adj[v]) + +in_edges{V}(v::V, g::HashUndirectedGraph{V}) = values(g.adj[v]) +in_degree{V}(v::V, g::HashUndirectedGraph{V}) = length(g.adj[v]) +in_neighbors{V}(v::V, g::HashUndirectedGraph{V}) = keys(g.adj[v]) + +has_vertex{V}(v::V, g::HashUndirectedGraph{V}) = haskey(g.adj,v) +has_edge{V,E}(e::E, g::HashUndirectedGraph{V,E}) = haskey(g.edges,e) +function has_edge_between(u::V, v::V, , g::HashUndirectedGraph{V}) = haskey(g.adj[u], v) + +function add_vertex!{V,E}(g::HashUndirectedGraph{V,E}, v::V) + if !haskey(g.adj, v) + g.adj[v]=Dict{V,E}() + end +end + +function delete_vertex!{V}(g::HashUndirectedGraph{V}, v::V) + if haskey(g.adj,v) + for u,e in g.adj[v] + delete!(g.adj[u], v) + delete!(g.edges, e) + end + end +end + +function add_edge!{V,E}(g::HashUndirectedGraph{V,E}, e::E, u::V, v::V) + if haskey(g.edges, e) + if !(g.edges[e] == (u,v) || g.edges[e] == (v,u)) + #yank out the old edge + u1,v1 = g.edges[e] + delete!(g.adj[u1], v1) + delete!(g.adv[v1], u1) + else + return g + end + end + g.adj[u][v] = e + g.adj[v][u] = e + g.edges[e] = (u,v) + g +end + +function delete_edge!{V,E}(e:E, g::HashUndirectedGraph{V,E}) + if haskey(g.edges, e) + u,v = g.edges[e] + delete!(g.adj[u],v) + delete!(g.adj[v],u) + delete!(g.edges, e) + end +end From 8c0e9002b85f6e50cdfdc4feebaada74ff01dcf7 Mon Sep 17 00:00:00 2001 From: David Einstein Date: Wed, 28 May 2014 15:32:14 -0400 Subject: [PATCH 05/13] dont need to reexport setindex and getindex --- src/Graphs.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Graphs.jl b/src/Graphs.jl index f8550519..2380d485 100644 --- a/src/Graphs.jl +++ b/src/Graphs.jl @@ -42,7 +42,7 @@ module Graphs vertex_property_requirement, vertex_property, AbstractVertexColormap, VectorVertexColormap, HashVertexColormap, - vertex_colormap_requirement, setindex!, getindex, + vertex_colormap_requirement, # edge_list GenericEdgeList, EdgeList, simple_edgelist, edgelist, From 9821140470e942f6de7e8b4c1da6479b0d5a43f5 Mon Sep 17 00:00:00 2001 From: David Einstein Date: Thu, 29 May 2014 22:29:43 -0400 Subject: [PATCH 06/13] interim cleanup --- doc/source/vertex_edge.rst | 23 ++++++++--- src/Graphs.jl | 11 ++---- src/a_star_spath.jl | 30 +++++---------- src/bellmanford.jl | 24 +++--------- src/common.jl | 78 +++++++++++++++----------------------- src/dijkstra_spath.jl | 26 ++++++------- src/kruskal_mst.jl | 8 +--- src/prim_mst.jl | 18 ++++----- test/a_star_spath.jl | 3 +- test/bellman_test.jl | 27 ++++++++----- test/dijkstra.jl | 3 +- 11 files changed, 106 insertions(+), 145 deletions(-) diff --git a/doc/source/vertex_edge.rst b/doc/source/vertex_edge.rst index 420b66e7..7b720449 100644 --- a/doc/source/vertex_edge.rst +++ b/doc/source/vertex_edge.rst @@ -105,12 +105,23 @@ Vertex Properties --------------- Many algorithms use a property of a vertex such as amount of a -resource provided or required by that vertex as input. As the -algorithms do not mandate any structure for the vertex types, these -vertex properties can be passed through to the algorithm by an -``VertexPropertyInspector``. An ``VertexPropertyInspector`` when -passed to the ``vertex_property`` method along with a vertex and a -graph, will return that property of a vertex. +resource provided or required by that vertex as input. These are +communicated to the code through the following functions: + +.. py::function:: vertex_property(i, v, g) +Returns the property of vertex ``v`` in graph ``g``. + +.. py::function:: vertex_property_requirement(i, v, g) +Checks that the graph ``g`` supports the interfaces necessary to +access the vertex property. + +.. py::function:: vertex_property_type(i, g) +Returns the type returned by ``vertex_property`` in graph ``g``. + +In all of these ``i`` is a type that indicates how the property is to +be obtained. The following example implementations are provided + +``Number``: If ``i`` is a ``Number`` then All vertex property inspectors should be declared as a subtype of ``AbstractVertexPropertyInspector{T}`` where ``T`` is the type of the diff --git a/src/Graphs.jl b/src/Graphs.jl index f8550519..cbdf2ae3 100644 --- a/src/Graphs.jl +++ b/src/Graphs.jl @@ -33,16 +33,11 @@ module Graphs add_edge!, add_vertex!, add_edges!, add_vertices!, - AbstractEdgePropertyInspector, VectorEdgePropertyInspector, - ConstantEdgePropertyInspector, AttributeEdgePropertyInspector, - edge_property, edge_property_requirement, - - AbstractVertexPropertyInspector, ConstantVertexPropertyInspector, - FunctionVertexPropertyInspector, VectorVertexPropertyInspector, - vertex_property_requirement, vertex_property, + edge_property_requirement, edge_property, edge_property_type, + vertex_property_requirement, vertex_property, vertex_property_type, AbstractVertexColormap, VectorVertexColormap, HashVertexColormap, - vertex_colormap_requirement, setindex!, getindex, + vertex_colormap_requirement, # edge_list GenericEdgeList, EdgeList, simple_edgelist, edgelist, diff --git a/src/a_star_spath.jl b/src/a_star_spath.jl index da546f9b..994723c7 100644 --- a/src/a_star_spath.jl +++ b/src/a_star_spath.jl @@ -17,12 +17,12 @@ using Base.Collections export shortest_path -function a_star_impl!{V,D,DH}( +function a_star_impl!{V}( graph::AbstractGraph{V},# the graph frontier, # an initialized heap containing the active vertices colormap::AbstractVertexColormap{Int}, # an (initialized) color-map to indicate status of vertices - edge_dists::AbstractEdgePropertyInspector{D}, # cost of each edge - heuristic::AbstractVertexPropertyInspector{DH}, # heuristic fn (under)estimating distance to target + edge_dists, # cost of each edge + heuristic, # heuristic fn (under)estimating distance to target t::V) # the end vertex while !isempty(frontier) @@ -30,7 +30,7 @@ function a_star_impl!{V,D,DH}( if u == t return path end - + for edge in out_edges(u, graph) v = target(edge) if colormap[v,graph] < 2 @@ -48,14 +48,15 @@ function a_star_impl!{V,D,DH}( end -function shortest_path{V,E,D,DH}( +function shortest_path{V,E}( graph::AbstractGraph{V,E}, # the graph - edge_dists::AbstractEdgePropertyInspector{D}, # cost of each edge + edge_dists, # cost of each edge s::V, # the start vertex t::V, # the end vertex - heuristic::AbstractVertexPropertyInspector{DH} = ConstantVertexPropertyInspector(0)) + heuristic=0) - # heuristic (under)estimating distance to target + # heuristic (under)estimating distance to target + D = edge_propety_type(edge_dists, graph) frontier = PriorityQueue{(D,Array{E,1},V),D}() frontier[(zero(D), E[], s)] = zero(D) if implements_vertex_map(graph) @@ -67,19 +68,6 @@ function shortest_path{V,E,D,DH}( a_star_impl!(graph, frontier, colormap, edge_dists, heuristic, t) end -function shortest_path{V,E,D}( - graph::AbstractGraph{V,E}, # the graph - edge_dists::Vector{D}, # cost of each edge - s::V, # the start vertex - t::V, # the end vertex - fheuristic::Function = n -> 0) - edge_len::AbstractEdgePropertyInspector{D} = VectorEdgePropertyInspector(edge_dists) - - heuristic = FunctionVertexPropertyInspector{D}(fheuristic) - shortest_path(graph, edge_len, s, t, heuristic) -end - - end using .AStar diff --git a/src/bellmanford.jl b/src/bellmanford.jl index b1f21065..57fe1753 100644 --- a/src/bellmanford.jl +++ b/src/bellmanford.jl @@ -25,7 +25,7 @@ end function bellman_ford_shortest_paths!{V,D}( graph::AbstractGraph{V}, - edge_dists::AbstractEdgePropertyInspector{D}, + edge_dists, sources::AbstractVector{V}, state::BellmanFordStates{V,D}) @@ -70,25 +70,19 @@ function bellman_ford_shortest_paths!{V,D}( end -function bellman_ford_shortest_paths{V,D}( +function bellman_ford_shortest_paths{V}( graph::AbstractGraph{V}, - edge_dists::AbstractEdgePropertyInspector{D}, + edge_dists, sources::AbstractVector{V}) + D = edge_property_type(edge_dists, graph) state = create_bellman_ford_states(graph, D) bellman_ford_shortest_paths!(graph, edge_dists, sources, state) end -function bellman_ford_shortest_paths{V,D}( - graph::AbstractGraph{V}, - edge_dists::Vector{D}, - sources::AbstractVector{V}) - edge_inspector = VectorEdgePropertyInspector{D}(edge_dists) - bellman_ford_shortest_paths(graph, edge_inspector, sources) -end -function has_negative_edge_cycle{V, D}( +function has_negative_edge_cycle{V}( graph::AbstractGraph{V}, - edge_dists::AbstractEdgePropertyInspector{D}) + edge_dists) try bellman_ford_shortest_paths(graph, edge_dists, vertices(graph)) catch e @@ -99,9 +93,3 @@ function has_negative_edge_cycle{V, D}( return false end -function has_negative_edge_cycle{V, D}( - graph::AbstractGraph{V}, - edge_dists::Vector{D}) - edge_inspector = VectorEdgePropertyInspector{D}(edge_dists) - has_negative_edge_cycle(graph, edge_inspector) -end diff --git a/src/common.jl b/src/common.jl index 08c4ed2b..0896e9fd 100644 --- a/src/common.jl +++ b/src/common.jl @@ -147,31 +147,24 @@ next(a::SourceIterator, s::Int) = ((e, s) = next(a.lst, s); (source(e, a.g), s)) # ################################################ -abstract AbstractVertexPropertyInspector{T} +#constant property +vertex_property(x::Number, v, g) = x +vertex_property_requirement(x, v, g) = none +vertex_property_type{T<:Number}(x::T, v, g) = T -vertex_property_requirement{T, V}(visitor::AbstractVertexPropertyInspector{T}, g::AbstractGraph{V}) = nothing +#vector property +vertex_property{V}(a::AbstractVector, v::V, g::AbstractGraph{V}) = a[vertex_index(v,g)] +vertex_property_requirement{V}(a::AbstractVector, g::AbstractGraph{V}) = @graph_requires g vertex_map +vertex_property_type{T}(a::AbstractVector{T}, g::AbstractGraph) = T -type ConstantVertexPropertyInspector{T} <: AbstractVertexPropertyInspector{T} - value::T -end - -vertex_property{T}(visitor::ConstantVertexPropertyInspector{T}, v, g) = visitor.value - -type VectorVertexPropertyInspector{T} <: AbstractVertexPropertyInspector{T} - values::Vector{T} -end +#attribute property +vertex_property(a::UTF8String, v::ExVertex, g::AbstractGraph{ExVertex}) = convert(Float64,v.attributes[a]) +vertex_property_type(a::UTF8String, g::AbstractGraph{ExVertex}) = Float64 -vertex_property{T,V}(visitor::VectorVertexPropertyInspector{T}, v::V, - g::AbstractGraph{V})= visitor.values[vertex_index(v,g)] +#function property +vertex_property(f::Function, v, g) = f(v) +vertex_property_type(f::Function, g) = Float64 -vertex_property_requirement{T, V}(visitor::VectorVertexPropertyInspector{T}, g::AbstractGraph{V}) = @graph_requires g vertex_map - - -type FunctionVertexPropertyInspector{T} <: AbstractVertexPropertyInspector{T} - f::Function -end - -vertex_property{T}(visitor::FunctionVertexPropertyInspector{T}, v, g) = visitor.f(v) ################################################# # @@ -179,32 +172,25 @@ vertex_property{T}(visitor::FunctionVertexPropertyInspector{T}, v, g) = visitor. # ################################################ -abstract AbstractEdgePropertyInspector{T} +#constant edge property +edge_property(x::Number, e, g) = x +edge_property_requirement(x, g) = none +edge_property_type{T<:Number}(x::T,g) = T -edge_property_requirement{T, V}(visitor::AbstractEdgePropertyInspector{T}, g::AbstractGraph{V}) = nothing +#vector edge property +edge_property{V,E}(a::AbstractVector, e::E, g::AbstractGraph{V,E}) = a[edge_index(e,g)] +edge_property_requirement{V,E}(a::AbstractVector, g::AbstractGraph{V,E}) = @graph_requires g edge_map +edge_property_type{T}(x::AbstractVector{T}, g::AbstractGraph) = T -type ConstantEdgePropertyInspector{T} <: AbstractEdgePropertyInspector{T} - value::T -end +#attribute property +edge_property(a::UTF8String, e::ExEdge, g::AbstractGraph) = convert(Float64,e.attributes[a]) +edge_property_type(a::UTF8String, g::AbstractGraph) = Float64 -edge_property{T}(visitor::ConstantEdgePropertyInspector{T}, e, g) = visitor.value +#function property +edge_property(f::Function, e, g) = f(e) +edge_property_type(f::Function, g) = Float64 -type VectorEdgePropertyInspector{T} <: AbstractEdgePropertyInspector{T} - values::Vector{T} -end - -edge_property{T,V}(visitor::VectorEdgePropertyInspector{T}, e, g::AbstractGraph{V}) = visitor.values[edge_index(e, g)] - -edge_property_requirement{T, V}(visitor::VectorEdgePropertyInspector{T}, g::AbstractGraph{V}) = @graph_requires g edge_map - -type AttributeEdgePropertyInspector{T} <: AbstractEdgePropertyInspector{T} - attribute::UTF8String -end - -function edge_property{T}(visitor::AttributeEdgePropertyInspector{T},edge::ExEdge, g) - convert(T,edge.attributes[visitor.attribute]) -end ################################################# # @@ -279,10 +265,10 @@ end isless{E,W}(a::WeightedEdge{E,W}, b::WeightedEdge{E,W}) = a.weight < b.weight -function collect_weighted_edges{V,E,W}(graph::AbstractGraph{V,E}, weights::AbstractEdgePropertyInspector{W}) +function collect_weighted_edges{V,E}(graph::AbstractGraph{V,E}, weights) edge_property_requirement(weights, graph) - + W = edge_property_type(weights, graph) wedges = Array(WeightedEdge{E,W}, 0) sizehint(wedges, num_edges(graph)) @@ -306,7 +292,3 @@ function collect_weighted_edges{V,E,W}(graph::AbstractGraph{V,E}, weights::Abstr return wedges end -function collect_weighted_edges{V,E,W}(graph::AbstractGraph{V,E}, weights::AbstractVector{W}) - visitor::AbstractEdgePropertyInspector{D} = VectorEdgePropertyInspector(edge_dists) - collect_weighted_edges(graph, visitor) -end diff --git a/src/dijkstra_spath.jl b/src/dijkstra_spath.jl index ad3c2cd5..2bbc311e 100644 --- a/src/dijkstra_spath.jl +++ b/src/dijkstra_spath.jl @@ -103,7 +103,7 @@ end function process_neighbors!{V,D,Heap,H}( state::DijkstraStates{V,D,Heap,H}, graph::AbstractGraph{V}, - edge_dists::AbstractEdgePropertyInspector{D}, + edge_dists, u::V, du::D, visitor::AbstractDijkstraVisitor) dists::Vector{D} = state.dists @@ -144,7 +144,7 @@ end function dijkstra_shortest_paths!{V, D, Heap, H}( graph::AbstractGraph{V}, # the graph - edge_dists::AbstractEdgePropertyInspector{D}, # distances associated with edges + edge_dists, # distances associated with edges sources::AbstractVector{V}, # the sources visitor::AbstractDijkstraVisitor, # visitor object state::DijkstraStates{V,D,Heap,H}) # the states @@ -203,11 +203,12 @@ function dijkstra_shortest_paths!{V, D, Heap, H}( end -function dijkstra_shortest_paths{V, D}( +function dijkstra_shortest_paths{V}( graph::AbstractGraph{V}, # the graph - edge_len::AbstractEdgePropertyInspector{D}, # distances associated with edges + edge_len, # distances associated with edges sources::AbstractVector{V}; visitor::AbstractDijkstraVisitor=TrivialDijkstraVisitor()) + D = edge_property_type(edge_dists, graph) state = create_dijkstra_states(graph, D) dijkstra_shortest_paths!(graph, edge_len, sources, visitor, state) end @@ -215,22 +216,21 @@ end # Convenient functions -function dijkstra_shortest_paths{V,D}( - graph::AbstractGraph{V}, edge_dists::Vector{D}, s::V; +function dijkstra_shortest_paths{V}( + graph::AbstractGraph{V}, edge_dists, s::V; visitor::AbstractDijkstraVisitor=TrivialDijkstraVisitor()) - - edge_len::AbstractEdgePropertyInspector{D} = VectorEdgePropertyInspector(edge_dists) + D = edge_property_type(edge_dists, graph) state = create_dijkstra_states(graph, D) - dijkstra_shortest_paths!(graph, edge_len, [s], visitor, state) + dijkstra_shortest_paths!(graph, edge_dists, [s], visitor, state) end -function dijkstra_shortest_paths{V,D}( - graph::AbstractGraph{V}, edge_dists::Vector{D}, sources::AbstractVector{V}; +function dijkstra_shortest_paths{V}( + graph::AbstractGraph{V}, edge_dists, sources::AbstractVector{V}; visitor::AbstractDijkstraVisitor=TrivialDijkstraVisitor()) - edge_len::AbstractEdgePropertyInspector{D} = VectorEdgePropertyInspector(edge_dists) + D = edge_property_type(edge_dists, graph) state = create_dijkstra_states(graph, D) - dijkstra_shortest_paths!(graph, edge_len, sources, visitor, state) + dijkstra_shortest_paths!(graph, edge_dists, sources, visitor, state) end function dijkstra_shortest_paths_withlog{V,D}( diff --git a/src/kruskal_mst.jl b/src/kruskal_mst.jl index 8a63b348..251c4c79 100644 --- a/src/kruskal_mst.jl +++ b/src/kruskal_mst.jl @@ -41,7 +41,7 @@ function kruskal_select{V,E,W}( return (re, rw) end -function kruskal_minimum_spantree(graph::AbstractGraph, eweights::AbstractEdgePropertyInspector; K::Integer=1) +function kruskal_minimum_spantree(graph::AbstractGraph, eweights; K::Integer=1) # collect & sort edges @@ -51,9 +51,3 @@ function kruskal_minimum_spantree(graph::AbstractGraph, eweights::AbstractEdgePr # select the tree edges kruskal_select(graph, wedges, K) end - - -function kruskal_minimum_spantree(graph::AbstractGraph, eweights::AbstractVector; K::Integer=1) - visitor::AbstractEdgePropertyInspector = VectorEdgePropertyInspector(eweights) - kruskal_minimum_spantree(graph, visitor, K=K) -end \ No newline at end of file diff --git a/src/prim_mst.jl b/src/prim_mst.jl index 5d68b284..fb844bdd 100644 --- a/src/prim_mst.jl +++ b/src/prim_mst.jl @@ -123,7 +123,7 @@ end function process_neighbors!{V,E,W,Heap,H}( graph::AbstractGraph{V,E}, # the graph - edge_weights::AbstractEdgePropertyInspector{W}, # weights associated with edges + edge_weights, # weights associated with edges visitor::AbstractPrimVisitor, # visitor object u::V, # the vertex whose neighbor to be examined state::PrimStates{V,W,Heap,H}) # the states (created) @@ -164,10 +164,10 @@ end function prim_minimum_spantree!{V,E,W,Heap,H}( graph::AbstractGraph{V,E}, # the graph - edge_weights::AbstractEdgePropertyInspector{W}, # weights associated with edges + edge_weights, # weights associated with edges root::V, # the root vertex visitor::AbstractPrimVisitor, # visitor object - state::PrimStates{V,W,Heap,H}) # the states (created) + state::PrimStates{V,W,Heap,H}) # the states (created) @graph_requires graph vertex_map incidence_list @@ -207,22 +207,21 @@ end function prim_minimum_spantree{V,E,W}( graph::AbstractGraph{V,E}, - edge_weight_vec::Vector{W}, + edge_weights::Vector{W}, root::V) state = create_prim_states(graph, W) visitor = default_prim_visitor(graph, W) - edge_weights = VectorEdgePropertyInspector(edge_weight_vec) prim_minimum_spantree!(graph, edge_weights, root, visitor, state) return (visitor.edges, visitor.weights) end -function prim_minimum_spantree{V,E,W}( +function prim_minimum_spantree{V,E}( graph::AbstractGraph{V,E}, - edge_weights::AbstractEdgePropertyInspector{W}, + edge_weights, root::V) - + W = edge_property_type(edge_weights, graph) state = create_prim_states(graph, W) visitor = default_prim_visitor(graph, W) prim_minimum_spantree!(graph, edge_weights, root, visitor, state) @@ -231,12 +230,11 @@ end function prim_minimum_spantree_withlog{V,E,W}( graph::AbstractGraph{V,E}, - edge_weight_vec::Vector{W}, + edge_weights::Vector{W}, root::V) state = create_prim_states(graph, W) visitor = LogPrimVisitor(STDOUT) - edge_weights = VectorEdgePropertyInspector(edge_weight_vec) prim_minimum_spantree!(graph, edge_weights, root, visitor, state) end diff --git a/test/a_star_spath.jl b/test/a_star_spath.jl index c230bb00..ec45725e 100644 --- a/test/a_star_spath.jl +++ b/test/a_star_spath.jl @@ -54,6 +54,5 @@ for i = 1 : ne add_edge!(g2, vs[we[1]], vs[we[2]]) end -sp2 = shortest_path(g2, VectorEdgePropertyInspector(eweights1), vs[1], vs[2], - VectorVertexPropertyInspector(g1_heuristics)) +sp2 = shortest_path(g2, eweights1, vs[1], vs[2], g1_heuristics) @test map(e -> edge_index(e, g2), sp2) == [2, 7, 15, 16] diff --git a/test/bellman_test.jl b/test/bellman_test.jl index d0eaf5de..af92f284 100644 --- a/test/bellman_test.jl +++ b/test/bellman_test.jl @@ -2,6 +2,11 @@ using Graphs using Base.Test +import Graphs.edge_property +import Graphs.edge_property_type +import Graphs.source +import Graphs.target +import Graphs.edge_index # g1: the example in CLRS (2nd Ed.) g1 = simple_inclist(5) @@ -42,9 +47,9 @@ immutable MyEdge{V} target::V dist::Float64 end -Graphs.target{V}(e::MyEdge{V}, g::AbstractGraph{V}) = e.target -Graphs.source{V}(e::MyEdge{V}, g::AbstractGraph{V}) = e.source -Graphs.edge_index(e::MyEdge) = e.index +target{V}(e::MyEdge{V}, g::AbstractGraph{V}) = e.target +source{V}(e::MyEdge{V}, g::AbstractGraph{V}) = e.source +edge_index(e::MyEdge) = e.index g2 = inclist([i for i=1:10], MyEdge{Int}) for i = 2:10 @@ -56,17 +61,19 @@ for i = 2:10 end end -type MyEdgePropertyInspector{T} <: AbstractEdgePropertyInspector{T} end +type MyEdgeInspector +end + +Graphs.edge_property(x::MyEdgeInspector, e::MyEdge, g::AbstractGraph) = e.dist +Graphs.edge_property_type(x::MyEdgeInspector, g::AbstractGraph) = Float64 -Graphs.edge_property{T,V}(inspector::MyEdgePropertyInspector{T}, e::MyEdge, g::AbstractGraph{V}) = e.dist -insp = MyEdgePropertyInspector{Float64}() -s2 = bellman_ford_shortest_paths(g2, insp, [1]) +s2 = bellman_ford_shortest_paths(g2, MyEdgeInspector(), [1]) @test s2.dists == [i * 1.0 for i=0:9] @test s2.parents == [i ==0 ? 1 : i for i = 0:9] -@test !has_negative_edge_cycle(g2, insp) +@test !has_negative_edge_cycle(g2, MyEdgeInspector()) add_edge!(g2, MyEdge{Int}(46, 10, 1, -10.0)) -@test has_negative_edge_cycle(g2, insp) -@test_throws NegativeCycleError bellman_ford_shortest_paths(g2, insp, [1]) +@test has_negative_edge_cycle(g2, MyEdgeInspector()) +@test_throws NegativeCycleError bellman_ford_shortest_paths(g2, MyEdgeInspector(), [1]) # g1: the example in CLR[~S] (1st Ed. Figure 25.7) g3 = simple_inclist(5) diff --git a/test/dijkstra.jl b/test/dijkstra.jl index e99c2a0c..5f3f32fa 100644 --- a/test/dijkstra.jl +++ b/test/dijkstra.jl @@ -51,8 +51,7 @@ for (i,v) in enumerate(g1_wedges) add_edge!(g1ex, ed) end -edgel = AttributeEdgePropertyInspector{Float64}("length") -s1ex = dijkstra_shortest_paths(g1ex, edgel, [1]) +s1ex = dijkstra_shortest_paths(g1ex, convert(UTF8String,"length"), [1]) @test s1ex.parents == [1, 3, 1, 2, 3] @test s1ex.dists == [0., 8., 5., 9., 7.] From 298e9a1680bbf99985fd0deef74220322c020dcb Mon Sep 17 00:00:00 2001 From: David Einstein Date: Thu, 29 May 2014 22:53:36 -0400 Subject: [PATCH 07/13] Fixed mysterious typo that occurred on merge. --- src/a_star_spath.jl | 2 +- src/hashgraph.jl | 72 --------------------------------------------- 2 files changed, 1 insertion(+), 73 deletions(-) delete mode 100644 src/hashgraph.jl diff --git a/src/a_star_spath.jl b/src/a_star_spath.jl index 994723c7..ee037469 100644 --- a/src/a_star_spath.jl +++ b/src/a_star_spath.jl @@ -56,7 +56,7 @@ function shortest_path{V,E}( heuristic=0) # heuristic (under)estimating distance to target - D = edge_propety_type(edge_dists, graph) + D = edge_property_type(edge_dists, graph) frontier = PriorityQueue{(D,Array{E,1},V),D}() frontier[(zero(D), E[], s)] = zero(D) if implements_vertex_map(graph) diff --git a/src/hashgraph.jl b/src/hashgraph.jl deleted file mode 100644 index 98eedba9..00000000 --- a/src/hashgraph.jl +++ /dev/null @@ -1,72 +0,0 @@ -type HashUndirectedGraph{V,E} <: AbstractGraph{V,E} - adj::Dict{V,Dict{V, E}} # u -> v -> edge(u,v) - edges::Dict{E,(V,V)} # edge -> (source, target) -} - -@graph_implements HashUndirectedGraph vertex_list edge_list -@graph_implements HashUndirectedGraph bidirectional_adjacency_list bidirectional_incidence_list - -source{V,E}(e::E, g::HashUndirectedGraph{V,E}) = g.edges[e][1] -target{V,E}(e::E, g::HashUndirectedGraph{V,E}) = g.edges[e][2] - - -is_directed(g::HashUndirectedGraph) = false - -num_vertices(g::HashUndirectedGraph) = length(g.adj) -vertices(g::HashUndirectedGraph) = keys(g.adj) - -num_edges(g::HashUndirectedGraph) = length(g.edges) -edges(g::HashUndirectedGraph) = keys(g.edges) - -out_edges{V}(v::V, g::HashUndirectedGraph{V}) = values(g.adj[v]) -out_degree{V}(v::V, g::HashUndirectedGraph{V}) = length(g.adj[v]) -out_neighbors{V}(v::V, g::HashUndirectedGraph{V}) = keys(g.adj[v]) - -in_edges{V}(v::V, g::HashUndirectedGraph{V}) = values(g.adj[v]) -in_degree{V}(v::V, g::HashUndirectedGraph{V}) = length(g.adj[v]) -in_neighbors{V}(v::V, g::HashUndirectedGraph{V}) = keys(g.adj[v]) - -has_vertex{V}(v::V, g::HashUndirectedGraph{V}) = haskey(g.adj,v) -has_edge{V,E}(e::E, g::HashUndirectedGraph{V,E}) = haskey(g.edges,e) -function has_edge_between(u::V, v::V, , g::HashUndirectedGraph{V}) = haskey(g.adj[u], v) - -function add_vertex!{V,E}(g::HashUndirectedGraph{V,E}, v::V) - if !haskey(g.adj, v) - g.adj[v]=Dict{V,E}() - end -end - -function delete_vertex!{V}(g::HashUndirectedGraph{V}, v::V) - if haskey(g.adj,v) - for u,e in g.adj[v] - delete!(g.adj[u], v) - delete!(g.edges, e) - end - end -end - -function add_edge!{V,E}(g::HashUndirectedGraph{V,E}, e::E, u::V, v::V) - if haskey(g.edges, e) - if !(g.edges[e] == (u,v) || g.edges[e] == (v,u)) - #yank out the old edge - u1,v1 = g.edges[e] - delete!(g.adj[u1], v1) - delete!(g.adv[v1], u1) - else - return g - end - end - g.adj[u][v] = e - g.adj[v][u] = e - g.edges[e] = (u,v) - g -end - -function delete_edge!{V,E}(e:E, g::HashUndirectedGraph{V,E}) - if haskey(g.edges, e) - u,v = g.edges[e] - delete!(g.adj[u],v) - delete!(g.adj[v],u) - delete!(g.edges, e) - end -end From 91f69aad64e3ccd1014489c0d1ede54a25e4681f Mon Sep 17 00:00:00 2001 From: David Einstein Date: Thu, 29 May 2014 23:09:44 -0400 Subject: [PATCH 08/13] backed out colormap changes --- src/a_star_spath.jl | 16 ++++++---------- src/common.jl | 35 ----------------------------------- 2 files changed, 6 insertions(+), 45 deletions(-) diff --git a/src/a_star_spath.jl b/src/a_star_spath.jl index ee037469..78e6c890 100644 --- a/src/a_star_spath.jl +++ b/src/a_star_spath.jl @@ -20,7 +20,7 @@ export shortest_path function a_star_impl!{V}( graph::AbstractGraph{V},# the graph frontier, # an initialized heap containing the active vertices - colormap::AbstractVertexColormap{Int}, # an (initialized) color-map to indicate status of vertices + colormap::Vector{Int}, # an (initialized) color-map to indicate status of vertices edge_dists, # cost of each edge heuristic, # heuristic fn (under)estimating distance to target t::V) # the end vertex @@ -33,8 +33,8 @@ function a_star_impl!{V}( for edge in out_edges(u, graph) v = target(edge) - if colormap[v,graph] < 2 - colormap[v,graph] = 1 + if colormap[vertex_index(v,graph)] < 2 + colormap[vertex_index(v,graph)] = 1 new_path = cat(1, path, edge) path_cost = cost_so_far + edge_property(edge_dists, edge, graph) enqueue!(frontier, @@ -42,7 +42,7 @@ function a_star_impl!{V}( path_cost + vertex_property(heuristic,v, graph)) end end - colormap[u,graph] = 2 + colormap[vertex_index(u,graph)] = 2 end nothing end @@ -59,12 +59,8 @@ function shortest_path{V,E}( D = edge_property_type(edge_dists, graph) frontier = PriorityQueue{(D,Array{E,1},V),D}() frontier[(zero(D), E[], s)] = zero(D) - if implements_vertex_map(graph) - colormap = VectorVertexColormap{Int}(zeros(Int, num_vertices(graph))) - else - colormap = HashVertexColormap{Int}(DefaultDict{V,Int}(0)) - end - colormap[s,graph] = 1 + colormap = zeros(Int, num_vertices(graph)) + colormap[vertex_index(s,graph)] = 1 a_star_impl!(graph, frontier, colormap, edge_dists, heuristic, t) end diff --git a/src/common.jl b/src/common.jl index 0896e9fd..7ee8bcea 100644 --- a/src/common.jl +++ b/src/common.jl @@ -191,41 +191,6 @@ edge_property(f::Function, e, g) = f(e) edge_property_type(f::Function, g) = Float64 - -################################################# -# -# vertex colormap -# -################################################ - -abstract AbstractVertexColormap{T} - -vertex_colormap_requirement{T, V}(color::AbstractVertexColormap{T}, - g::AbstractGraph{V}) = nothing - -type VectorVertexColormap{T} <: AbstractVertexColormap{T} - values::Vector{T} -end - -vertex_colormap_requirement{T, V}(color::VectorVertexColormap{T}, - g::AbstractGraph{V}) = @graph_requires g vertex_map - -getindex{T,V}(color::VectorVertexColormap{T}, - v::V, g::AbstractGraph{V}) = color.values[vertex_index(v,g)] - -setindex!{T,V}(color::VectorVertexColormap{T}, x::T, - v::V, g::AbstractGraph{V}) = color.values[vertex_index(v,g)]=x - -type HashVertexColormap{T, V} <: AbstractVertexColormap{T} - values::Dict{V,T} -end - -getindex{T,V}(color::HashVertexColormap{T}, - v::V, g::AbstractGraph{V}) = color.values[v,g] - -setindex!{T,V}(color::HashVertexColormap{T}, x::T, - v::V, g::AbstractGraph{V}) = color.values[v]=x - ################################################# # # convenient functions From 8074764f1ddae415ac5106d9c29473d8c92ea593 Mon Sep 17 00:00:00 2001 From: David Einstein Date: Thu, 29 May 2014 23:23:06 -0400 Subject: [PATCH 09/13] kinda fixed doco --- doc/source/vertex_edge.rst | 89 +++++++++++++------------------------- 1 file changed, 31 insertions(+), 58 deletions(-) diff --git a/doc/source/vertex_edge.rst b/doc/source/vertex_edge.rst index 7b720449..81ae45ff 100644 --- a/doc/source/vertex_edge.rst +++ b/doc/source/vertex_edge.rst @@ -106,12 +106,12 @@ Vertex Properties Many algorithms use a property of a vertex such as amount of a resource provided or required by that vertex as input. These are -communicated to the code through the following functions: +communicated to the code through the following methods: .. py::function:: vertex_property(i, v, g) Returns the property of vertex ``v`` in graph ``g``. -.. py::function:: vertex_property_requirement(i, v, g) +.. py::function:: vertex_property_requirement(i, g) Checks that the graph ``g`` supports the interfaces necessary to access the vertex property. @@ -119,80 +119,53 @@ access the vertex property. Returns the type returned by ``vertex_property`` in graph ``g``. In all of these ``i`` is a type that indicates how the property is to -be obtained. The following example implementations are provided - -``Number``: If ``i`` is a ``Number`` then - -All vertex property inspectors should be declared as a subtype of -``AbstractVertexPropertyInspector{T}`` where ``T`` is the type of the -vertex property. The vertex propery inspector should respond to the -following methods. - -.. py::function:: vertex_property(i, e, g) - - returns the vertex property of vertex ``v`` in graph ``g`` selected by - inspector ``i``. - -.. py::function:: vertex_property_requirement(i, g) - - checks that graph ``g`` implements the interface(s) necessary for - inspector ``i`` +be obtained, both by influencing whish method is chosen and providing +information to that method. The following example implementations are provided: -Three vertex property inspectors are provided -``ConstantVertexPropertyInspector``, ``VectorVertexPropertyInspector`` and -``AttributeVertexPropertyInspector``. +``Number``: If ``i`` is a ``Number`` then each vertex is given that +value. -``ConstantVertexPropertyInspector(c)`` constructs a vertex property -inspector that returns the constant ``c`` for each vertex. +``AbstractVector``: If ``i`` is an ``AbstractVector`` then each +vertex ``v`` has value ``i[vertex_index(v,g)]``. -``VectorVertexPropertyInspector(vec)`` constructs a vertex property -inspector that returns ``vec[vertex_index(v, g)]``. It requires that -``g`` implement the ``vertex_map`` interface. +``UTF8String``: If ``i`` is an ``UTF8String`` and ``v`` is an +``ExVertex`` then the the vertex has value ``v.attributes[i]``. -``FunctionVertexPropertyInspector(func)`` constructs a vertex property -inspector that returns the result of ``func(v)`` from an ``ExVertex``. -``AttributeVertexPropertyInspector`` requires that the graph implements -the ``vertex_map`` interface. +``Function``: If ``i`` is a ``Function`` then ``v`` has value ``i(v)``. Edge Properties --------------- + Many algorithms use a property of an edge such as length, weight, flow, etc. as input. As the algorithms do not mandate any structure -for the edge types, these edge properties can be passed through to the -algorithm by an ``EdgePropertyInspector``. An -``EdgePropertyInspector`` when passed to the ``edge_property`` method -along with an edge and a graph, will return that property of an edge. - -All edge property inspectors should be declared as a subtype of -``AbstractEdgePropertyInspector{T}`` where ``T`` is the type of the -edge property. The edge propery inspector should respond to the -following methods. +for the edge types, these edge properties are +communicated to the code through the following methods (analogous to +the vertex meghods: .. py::function:: edge_property(i, e, g) - - returns the edge property of edge ``e`` in graph ``g`` selected by - inspector ``i``. +Returns the property of edge ``e`` in graph ``g``. .. py::function:: edge_property_requirement(i, g) +Checks that the graph ``g`` supports the interfaces necessary to +access the edge property. - checks that graph ``g`` implements the interface(s) necessary for - inspector ``i`` +.. py::function:: vertex_property_type(i, g) +Returns the type returned by ``edge_property`` in graph ``g``. + +In all of these ``i`` is a type that indicates how the property is to +be obtained, both by influencing whish method is chosen and providing +information to that method. The following example implementations are provided: -Three edge property inspectors are provided -``ConstantEdgePropertyInspector``, ``VectorEdgePropertyInspector`` and -``AttributeEdgePropertyInspector``. +``Number``: If ``i`` is a ``Number`` then each edge is given that +value. -``ConstantEdgePropertyInspector(c)`` constructs an edge property -inspector that returns the constant ``c`` for each edge. +``AbstractVector``: If ``i`` is an ``AbstractVector`` then each +edge ``e`` has value ``i[vertex_index(e,g)]``. -``VectorEdgePropertyInspector(v)`` constructs an edge property -inspector that returns ``v[edge_index(e, g)]``. It requires that -``g`` implement the ``edge_map`` interface. +``UTF8String``: If ``i`` is an ``UTF8String`` and ``e`` is an +``ExEdge`` then the the vertex has value ``e.attributes[i]``. -``AttributeEdgePropertyInspector(name)`` constructs an edge property -inspector that returns the named attribute from an ``ExEdge``. -``AttributeEdgePropertyInspector`` requires that the graph implements -the ``edge_map`` interface. +``Function``: If ``i`` is a ``Function`` then ``e`` has value ``i(e)``. From 0025cada08e7b25bf155669ea871a9e686a08d1f Mon Sep 17 00:00:00 2001 From: David Einstein Date: Fri, 30 May 2014 07:55:22 -0400 Subject: [PATCH 10/13] Made the code less 'convent'ional (removed 'none') Fixed speeling error. --- doc/source/vertex_edge.rst | 2 +- src/common.jl | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/source/vertex_edge.rst b/doc/source/vertex_edge.rst index 81ae45ff..6bcbe598 100644 --- a/doc/source/vertex_edge.rst +++ b/doc/source/vertex_edge.rst @@ -119,7 +119,7 @@ access the vertex property. Returns the type returned by ``vertex_property`` in graph ``g``. In all of these ``i`` is a type that indicates how the property is to -be obtained, both by influencing whish method is chosen and providing +be obtained, both by influencing which method is chosen and providing information to that method. The following example implementations are provided: ``Number``: If ``i`` is a ``Number`` then each vertex is given that diff --git a/src/common.jl b/src/common.jl index 7ee8bcea..1307af53 100644 --- a/src/common.jl +++ b/src/common.jl @@ -149,7 +149,7 @@ next(a::SourceIterator, s::Int) = ((e, s) = next(a.lst, s); (source(e, a.g), s)) #constant property vertex_property(x::Number, v, g) = x -vertex_property_requirement(x, v, g) = none +vertex_property_requirement(x, v, g) = nothing vertex_property_type{T<:Number}(x::T, v, g) = T #vector property @@ -174,7 +174,7 @@ vertex_property_type(f::Function, g) = Float64 #constant edge property edge_property(x::Number, e, g) = x -edge_property_requirement(x, g) = none +edge_property_requirement(x, g) = nothing edge_property_type{T<:Number}(x::T,g) = T #vector edge property From 52900f386408ef64b3d5af11ea6873f11587b8c0 Mon Sep 17 00:00:00 2001 From: David Einstein Date: Sun, 1 Jun 2014 21:51:56 -0400 Subject: [PATCH 11/13] Extracted the non general property extractors from the library, put them as examples in test. Still need to try documentation. --- test/dijkstra.jl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/dijkstra.jl b/test/dijkstra.jl index 5f3f32fa..3cce6bbd 100644 --- a/test/dijkstra.jl +++ b/test/dijkstra.jl @@ -51,6 +51,13 @@ for (i,v) in enumerate(g1_wedges) add_edge!(g1ex, ed) end +import Graphs.edge_property +import Graphs.edge_property_type + +edge_property(a::UTF8String, e::ExEdge, g::AbstractGraph) = convert(Float64,e.attributes[a]) +edge_property_type(a::UTF8String, g::AbstractGraph) = Float64 + + s1ex = dijkstra_shortest_paths(g1ex, convert(UTF8String,"length"), [1]) @test s1ex.parents == [1, 3, 1, 2, 3] From 2056bc2d72f2ef7daa89226265369c1fac51961c Mon Sep 17 00:00:00 2001 From: David Einstein Date: Sun, 1 Jun 2014 23:00:26 -0400 Subject: [PATCH 12/13] removed non general inspectors from common.jl --- src/common.jl | 18 ------------------ test/a_star_spath.jl | 6 ++++++ 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/src/common.jl b/src/common.jl index 1307af53..77f81042 100644 --- a/src/common.jl +++ b/src/common.jl @@ -157,15 +157,6 @@ vertex_property{V}(a::AbstractVector, v::V, g::AbstractGraph{V}) = a[vertex_inde vertex_property_requirement{V}(a::AbstractVector, g::AbstractGraph{V}) = @graph_requires g vertex_map vertex_property_type{T}(a::AbstractVector{T}, g::AbstractGraph) = T -#attribute property -vertex_property(a::UTF8String, v::ExVertex, g::AbstractGraph{ExVertex}) = convert(Float64,v.attributes[a]) -vertex_property_type(a::UTF8String, g::AbstractGraph{ExVertex}) = Float64 - -#function property -vertex_property(f::Function, v, g) = f(v) -vertex_property_type(f::Function, g) = Float64 - - ################################################# # # Edge Property Inspectors @@ -182,15 +173,6 @@ edge_property{V,E}(a::AbstractVector, e::E, g::AbstractGraph{V,E}) = a[edge_inde edge_property_requirement{V,E}(a::AbstractVector, g::AbstractGraph{V,E}) = @graph_requires g edge_map edge_property_type{T}(x::AbstractVector{T}, g::AbstractGraph) = T -#attribute property -edge_property(a::UTF8String, e::ExEdge, g::AbstractGraph) = convert(Float64,e.attributes[a]) -edge_property_type(a::UTF8String, g::AbstractGraph) = Float64 - -#function property -edge_property(f::Function, e, g) = f(e) -edge_property_type(f::Function, g) = Float64 - - ################################################# # # convenient functions diff --git a/test/a_star_spath.jl b/test/a_star_spath.jl index ec45725e..5ba1135d 100644 --- a/test/a_star_spath.jl +++ b/test/a_star_spath.jl @@ -43,6 +43,12 @@ for i = 1 : ne eweights1[i] = we[3] end +import Graphs.vertex_property +import Graphs.vertex_property_type + +vertex_property(f::Function, v, g) = f(v) +vertex_property_type(f::Function, g) = Float64 + sp = shortest_path(g1, eweights1, 1, 2, n -> g1_heuristics[n]) edge_numbers = map(e -> edge_index(e, g1), sp) @test edge_numbers == [2, 7, 15, 16] From 42af31269a011e76eb7b31918b0cc9f069888488 Mon Sep 17 00:00:00 2001 From: David Einstein Date: Wed, 4 Jun 2014 00:06:49 -0400 Subject: [PATCH 13/13] brought documentation up to date --- doc/source/vertex_edge.rst | 54 +++++++++++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 7 deletions(-) diff --git a/doc/source/vertex_edge.rst b/doc/source/vertex_edge.rst index 6bcbe598..665c11c3 100644 --- a/doc/source/vertex_edge.rst +++ b/doc/source/vertex_edge.rst @@ -101,6 +101,22 @@ Both edge types implement the following methods: A custom edge type ``E{V}`` which is constructible by ``E(index::Int, s::V, t::V)`` and implements the above methods is usable in the ``VectorIncidenceList`` parametric type. Construct such a list with ``inclist(V,E{V})``, where E and V are your vertex and edge types. See test/inclist.jl for an example. +Properties +-------- + +In order to link real world problems to the graph algorithms we need +to assign properties such as weight, length, flow color, etc. to the +vertices or edges. There are many ways to assign properties to the +vertices and edges, but the algorithms should not have to worry about +how to access the property. + +In order to communicate the properties to the algorithm we pass an +object ``i`` that tells the algorithm how to get the data. The +algorithm then calls ``vertex_property(i, v, g)`` or +``edge_property(i, e, g)`` to get the value of the property. The +julia dispatcher uses the type of ``i`` along with the edge or vertex +and graph types to determine the appropriate method to call. + Vertex Properties --------------- @@ -128,10 +144,38 @@ value. ``AbstractVector``: If ``i`` is an ``AbstractVector`` then each vertex ``v`` has value ``i[vertex_index(v,g)]``. -``UTF8String``: If ``i`` is an ``UTF8String`` and ``v`` is an -``ExVertex`` then the the vertex has value ``v.attributes[i]``. +If some other method is desired you can overload the +``vertex_property`` and ``vertex_property_type`` functions. + +For example, if your vertex type looked like +``` +type MyVertex +index::Int +name::ASCIIString +production::Float64 +capacity::Float64 +``` +and you want to pass the production field to an algorithm. First you +would declare a type for the julia dispatcher to key on (you could +use an existing type, but would probably confuse someone reading the +code.) +``` +type ProductionInspector +end +``` +and provide implementations of ``vertex_property`` and +``vertex_property_type`` (``vertex_property_requirement`` defaults to +``nothing`` and since we have no requirements, we can leave it as is.) +``` +import Graphs: vertex_property, vertex_property_type + +vertex_property(i::ProductionInspector,v::MyVertex,g::AbstractGraph)=v.production +vertex_property_type(i::ProductionInspector,v::MyVertex,g::AbstractGraph)=Float64 +``` +and then pass an instance of ``ProductionInspector`` to the +algorithm. The julia optimizer seems to do a good job of optimizing +away all of the dispatching logic. -``Function``: If ``i`` is a ``Function`` then ``v`` has value ``i(v)``. @@ -165,7 +209,3 @@ value. ``AbstractVector``: If ``i`` is an ``AbstractVector`` then each edge ``e`` has value ``i[vertex_index(e,g)]``. -``UTF8String``: If ``i`` is an ``UTF8String`` and ``e`` is an -``ExEdge`` then the the vertex has value ``e.attributes[i]``. - -``Function``: If ``i`` is a ``Function`` then ``e`` has value ``i(e)``.