Reputation: 656
I'd like to assign a small, non-negative edge weights to certain edges used in a shortest path. Here is an example graph:
library(igraph)
data <- read.table(text="
1 2
1 4
1 5
2 3
2 4
3 4
5 7
5 8
3 6", header=FALSE)
gmatrix <- data.matrix(data, rownames.force = NA) #convert into a matrix to use in igraph
g <- graph_from_edgelist(gmatrix, directed = FALSE)
If I find the shortest path between node 1 and node 3, the edges used are 1-2 and 1-3.
get.shortest.paths(g, 1,3)
$vpath
$vpath[[1]]
+ 3/9 vertices, from 634c426:
[1] 1 2 3
What I want to do is to assign a small epsilon value to those edges. Then, I'd like to call get.shortest.paths(g, 1,3)
to test whether the function will identify the same path or not.
Upvotes: 2
Views: 1758
Reputation: 76402
In the code that follows I will use function all_shortest_paths
, not get.shortest.paths
, to get all shortest paths. This is because I will later assign weights to the edges of one of them.
The paths asked are between vertices 3
and 5
, since there are two paths.
First, see what get.shortest.paths
returns.
get.shortest.paths(g, 3, 5)
#$vpath
#$vpath[[1]]
#+ 4/8 vertices, from 98e8e26:
#[1] 3 2 1 5
#
#
#$epath
#NULL
#
#$predecessors
#NULL
#
#$inbound_edges
#NULL
The function returns just one path: 3 2 1 5
. But there are two shortest paths between vertices 3
and 5
.
p <- all_shortest_paths(g, 3, 5)
p
#$res
#$res[[1]]
#+ 4/8 vertices, from fc330b4:
#[1] 3 2 1 5
#
#$res[[2]]
#+ 4/8 vertices, from fc330b4:
#[1] 3 4 1 5
#
#
#$nrgeo
#[1] 2 1 1 1 2 1 0 0
Now assign epsilon weights to the edges of one of the paths, the first one.
E(g, path = p$res[[1]])$weight <- .Machine$double.eps^0.5
E(g)$weight
#[1] 1.490116e-08 NA 1.490116e-08 1.490116e-08 NA
#[6] NA NA NA NA
Get all shortest paths again.
all_shortest_paths(g, 3, 5)
#$res
#$res[[1]]
#+ 4/8 vertices, from fc330b4:
#[1] 3 4 1 5
#
#
#$nrgeo
#[1] 1 0 1 1 1 1 0 0
Only one path now, path 3 4 1 5
, former path p$res[[1]]
is now heavier, no longer a shortest path.
And get.shortest.paths
also returns the one path.
get.shortest.paths(g, 3, 5)
#$vpath
#$vpath[[1]]
#+ 4/8 vertices, from 98e8e26:
#[1] 3 4 1 5
#
#
#$epath
#NULL
#
#$predecessors
#NULL
#
#$inbound_edges
#NULL
EDIT.
Following the comment by user paqmo, the following code uses only function get.shortest.paths
to get a shortest path. After assigning weights to its edges, the path returned by the same function is no longer p2
, it's the same as in the code above.
This code only makes sense if the graph is reinitialized with no weights attribute.
p2 <- get.shortest.paths(g, 3, 5)
p2
#$vpath
#$vpath[[1]]
#+ 4/8 vertices, from 61bfc89:
#[1] 3 2 1 5
#
#
#$epath
#NULL
#
#$predecessors
#NULL
#
#$inbound_edges
#NULL
E(g, path = p2$vpath[[1]])$weight <- .Machine$double.eps^0.5
E(g)$weight
get.shortest.paths(g, 3, 5)
#$vpath
#$vpath[[1]]
#+ 4/8 vertices, from 61bfc89:
#[1] 3 4 1 5
#
#
#$epath
#NULL
#
#$predecessors
#NULL
#
#$inbound_edges
#NULL
Upvotes: 1
Reputation: 3729
Ok, this I can help with:
Use E()
to query the edges with the ids grabbed from get.shortest.paths
and assign the values to a new edge attribute name (e.g., "weight" or whatever):
p <- get.shortest.paths(g, 1, 3)$vpath[[1]]
E(g, path = p)$weight <- 0.1
> E(g)
+ 9/9 edges from 605e8c7:
[1] 1--2 1--4 1--5 2--3 2--4 3--4 5--7 5--8 3--6
> E(g)$weight
[1] 0.1 NA NA 0.1 NA NA NA NA NA
The path from 1 to 2 and 2 to 3 now has a weighted edge.
Now, assign zero to the other edges and 'get.shortest.paths` identifies another path:
> E(g)$weight <- ifelse(is.na(E(g)$weight), 0, E(g)$weight)
> E(g)$weight
[1] 0.1 0.0 0.0 0.1 0.0 0.0 0.0 0.0 0.0
> get.shortest.paths(g, 1, 3, weights = E(g)$weight)
$vpath
$vpath[[1]]
+ 3/8 vertices, from 605e8c7:
[1] 1 4 3
$epath
NULL
$predecessors
NULL
$inbound_edges
NULL
A bit more concise:
g <- set_edge_attr(g, "weight", value = ifelse(E(g) %in% E(g, path = p), 0.1, 0))
E(g)$weight
[1] 0.1 0.0 0.0 0.1 0.0 0.0 0.0 0.0 0.0
Upvotes: 1