How can I create a Static Directed Graph from an array of tuples in Julia without having to create a Simple Directed Graph first. An example edge list I have is [(1,2),(2,3),(3,4)]. The documentation of StaticGraphs.jl is limited.
There's a way to do this but it requires you to have the edges and their reverses already sorted into two vectors. Assume you have a directed path graph 1 -> 2 -> 3 -> 4:
fwd = [(1, 2), (2, 3), (3, 4)] # these are your forward edges, sorted
rev = [(2, 1), (3, 2), (4, 3)] # these are the reverse of the forward edges, sorted
# also, sort(reverse.(fwd)) will do this easily.
g = StaticDiGraph(4, fwd, rev) # number of vertices is the first argument
testing:
julia> h = StaticDiGraph(path_digraph(4))
{4, 3} directed simple static {UInt8, UInt8} graph
julia> g == h
true
Related
I want to calculate the Euclidean distance between a tuple and each tuple within a Vector in Julia using the map function, like below (but I get two values instead of three):
julia> tups = [
(1, 3),
(11, 2),
(0, 1)
];
julia> map((x, y) -> √(sum((x.-y).^2)), tups, (3, 3))
2-element Vector{Float64}:
2.0
8.06225774829855
How can I make it work correctly?
Julia has the Distances package especially for these types of calculations. The 'Julian way' encourages interoperability between packages to allow benefitting from future development of the ecosystem. For example, new metric definitions, or specialized hardware code to compute distances.
For the problem in the post, the code would look:
julia> using Distances
julia> tups = [
(1, 3),
(11, 2),
(0, 1)
];
julia> euclidean.(tups,Ref((3,3)))
3-element Vector{Float64}:
2.0
8.06225774829855
3.605551275463989
Notice the use of broadcasting instead of map with dot syntax euclidean.. The Ref((3,3)) causes broadcasting to consider (3,3) as a single element to broadcast and not break it to a pair of Ints.
The code you've written is pretty equal to this:
[
func((1, 3), 3),
func((11, 2), 3)
]
The map function iterates over the given collections iter times equal to the lowest length:
julia> length((3, 3)), length(tups)
(2, 3)
So it iterates two times, not three. To make that work, you can repeat the (3, 3), three times or even omit the (3, 3) argument:
julia> map((x, y) -> √(sum((x.-y).^2)), tups, ((3, 3), (3, 3), (3, 3)))
3-element Vector{Float64}:
2.0
8.06225774829855
3.605551275463989
# OR
julia> map((x, y) -> √(sum((x.-y).^2)), tups, ((3, 3) for _∈1:3))
3-element Vector{Float64}:
2.0
8.06225774829855
3.605551275463989
# Or omit the last argument
julia> map(arg -> √((3 - arg[1])^2 + (3 - arg[2])^2), tups)
3-element Vector{Float64}:
2.0
8.06225774829855
3.605551275463989
We can obtain the incidence matrix of a digraph using the method incidence_matrix(oriented=None, sparse=True, vertices=None) in SageMath.
Each row is a vertex, and each column is an edge. The vertices are ordered as obtained by the method vertices(), except when parameter vertices is given, and the edges as obtained by the method edge_iterator().
My question is how to specify the vertice order and the edge order?
For example, g is a weighted digraph with 10 edges:
edges = [('s', 'x', 3), ('s', 'y', 5),
('x', 'y', 2), ('x', 'z', 6),
('y', 'x', 1), ('y', 'z', 4), ('y', 't', 6),
('z', 't', 2),
('t', 's', 3), ('t', 'z', 7)]
g = DiGraph(edges)
I want to arrange the incidence matrix such that the vertices (from top to down) are ordered as s, x, y, z, t and the edges are ordered (from left to right) as those in edges (i.e., listing the edges in the alphabetic order s, x, y, z, t).
A quick look at the code (which you can obtain by doing g.edge_iterator??) for edge_iterator() suggests
The iterator returned is over the edges incident with any vertex
given in the parameter "vertices".
if oriented:
for e, (i, j) in enumerate(self.edge_iterator(labels=False)):
if i != j:
m[verts[i],e] = -1
m[verts[j],e] = +1
else:
for e, (i, j) in enumerate(self.edge_iterator(labels=False)):
m[verts[i],e] += 1
m[verts[j],e] += 1
tells me that probably one would have to hack the code for this a bit to change the order.
This seems like a reasonable request to have this customizable, so I've opened Sage Trac ticket 27513 for this.
I am adding edges to a simple weighted directed graph (from SimpleWeightedDiGraph() that is part of LightGraphs package) in Julia. Some of the arcs are "free" (null weight). However, when specifying the weight of 0 it is not added as a new edge and a shortest path problem does not include it in the possible solution. Is there an easy way to add "free" edges/arcs to a graph in Julia?
The key issue is how zero values are represented in a sparse matrix (which is the underlying data store for SimpleWeightedGraphs. While it is true that the underlying zero value is preserved once it's explicitly set:
julia> g = SimpleWeightedGraph(6)
{6, 0} undirected simple Int64 graph with Float64 weights
julia> add_edge!(g, 1, 2, 1.0)
true
julia> add_edge!(g, 1, 3, 1.0)
true
julia> add_edge!(g, 1, 3, 0.0)
true
julia> weights(g)
6×6 SparseMatrixCSC{Float64,Int64} with 4 stored entries:
[2, 1] = 1.0
[3, 1] = 0.0
[1, 2] = 1.0
[1, 3] = 0.0
this will fail if you have to do anything with the edges:
julia> collect(edges(g))
1-element Array{SimpleWeightedGraphs.SimpleWeightedEdge{Int64,Float64},1}:
Edge 1 => 2 with weight 1.0
There's no really good solution to this. My advice is to use a sufficiently small weight as proposed above to approximate a zero value.
(PS: the reason the initial add_edge!(g, 1, 3, 0.0) doesn't work is because in Julia, setting the value of a new sparsematrix element to zero is a no-op.)
This modification of the SimpleWeightedGraphs README example works for me:
using LightGraphs, SimpleWeightedGraphs
# set the size of the graph
g = SimpleWeightedDiGraph(3)
add_edge!(g, 1, 2, 0.5)
add_edge!(g, 2, 3, 0.8)
add_edge!(g, 1, 3, 2.0)
# find the shortest path from vertex 1 to vertex 3 taking weights into account.
enumerate_paths(dijkstra_shortest_paths(g, 1), 3) # gives [1,2,3]
# reweight the edge from 1 to 3 to be "free"
add_edge!(g, 1, 3, 0.0)
enumerate_paths(dijkstra_shortest_paths(g, 1), 3) # gives [1,3]
Notice that the vertices must be in the graph (according to its size) to be able to set their weights, as stated in the docs: ?add_edge!.
I have array of x integers and i need to answer y queries. Each query have 3 integers ( Number, Left index, Right Index). I need to calculate GCD(Number, array[i]). i is in the range left-right as as specified in the query. Now i need to output the maximum number that i can obtain in the GCD calculation.
Example--> Suppose numbers are 4 5 8 Query-> (6,1,3)---(Number,Left Index,Right index) GCD(6,4) = 2 GCD(6,5) = 1 GCD(6,8) = 2
So answer is 2. What if i have 10^5 elements in the array and i need to answer 10^5 queries ?
I am thinking to do some preprocessing but not getting any idea.
It is possible to store index for each prime that is in factorization of array elements, and for query number look at indices of it's factorization in range that is given and find maximal GCD between them.
Indices can be implemented as lists with pairs (position in array, prime power), with that searching for segment is in log.
E.g. if array is [4, 5, 8, 12, 3] than we have 3 different primes (2, 3, 5) and indices:
2 -> [(0, 4), (2, 8), (3, 4)]
3 -> [(3, 3), (4, 3)]
5 -> [(1,5)]
For query (6, 1, 3), since 6=2*3 has to look in sub-indices:
2 -> [(2, 8), (3, 4)]
3 -> [(3, 3)]
Going 'parallel' through these sub-indices, and making product of GCD's for primes (minimum of prime power in query number and index second element) will produce all possible GCD's.
In graph theory, we use the Hungarian Algorithm to compute a weighted bipartite graph's minimum edge cover (a set of edges that is incident to every vertices, the one with the minimum total weight.)
I find that in new version 8 of Mathematica, there is a whole new package of functions for Graph Theory, (begin with Graph[].) But I've not found any function that do this job. I do find a function called FindEdgeCover[] that can only find a edge cover, not the minimum one.
I did a few experiments and, although not documented, it seems that FindEdgeCover[] does what you want.
Consider for example:
h[list_] := CompleteGraph[4, EdgeWeight -> list]
FindEdgeCover[h#Range#6]
(*
-> {1->2,1->3,1->4}
*)
But
FindEdgeCover[h#Reverse#Range#6]
(*
-> {1->2,3->4}
*)
of course no warranty ...
Edit
Here you have some code to experiment with by using different weighted adjacency matrices
adj = {{\[Infinity], 1, 1, 1, 1}, {1, \[Infinity], 2, 2, 2},
{1, 2, \[Infinity], 2, 2}, {1, 2, 2, \[Infinity], 2},
{1, 2, 2, 2, \[Infinity]}}
g = WeightedAdjacencyGraph[adj];
g = WeightedAdjacencyGraph[adj, VertexShapeFunction -> "Name",
EdgeLabels ->
MapThread[
Rule, {EdgeList#g, AbsoluteOptions[g, EdgeWeight] /. {_ -> x_} -> x}],
GraphHighlight -> FindEdgeCover[g]]
NB: The code is not good at all, but I couldn't find a way to use EdgeLabels -> “EdgeWeight”. I posted this question to see if someone can do it.