Count unique triangles in a network - r

Using iGraph I can count the number of triangles a given vertex is part of, but I can't find a way to simply count the number of unique triangles within a network. For instance, we create a network that forms two distinct triangles: A-B-D, B-C-E
library(igraph)
edges <- data.frame("vertex1" = c("A","A","B","B","B","C"),"vertex2"= c("B","D","D","C","E","E"))
example_graph <- graph_from_data_frame(edges, directed = FALSE)
If I run sum(count_triangles()) I get a result of 6
> sum(count_triangles(example_graph))
[1] 6
This makes sense because this is merely summing the number of triangles each vertex belongs to: A = 1, B = 2, C = 1, D = 1, E = 1.
However, we can see that there are only two distinct triangles:
> triangles(example_graph)
+ 6/5 vertices, named, from 9c62b6b:
[1] B A D B C E
Is there a way to count only unique triangles in the graph? So that I get an answer of 2 to the above? In my actual data I have thousands of vertices and a few million edges so calculating the number of unique triangles manually isn't an option. Should I simply use length(triangles(example_graph))/3 ?

Related

Number of ties repetition among vertices

I have an undirected graph with 343 nodes and 4000+ edges. These nodes are connected to each other by different type of ties. Imagine I have A, B, C, D, E as nodes and tie 1, tie 2, and tie 3. I have organized my dataframe as below:
Column1 Column2 Column3
node1 node2 tie
A C 1
C A 3
D A 2
B A 2
A B 1
As the example above can show, A and C and A and B have been linked with each other twice, regardless of their tie and whether they belong to "node1" or "node2" column. And the sum of these repetitions for the whole network is 4.
I exactly want to get this sum for my graph with 4000+ edges. Also would be cool to see the number of repeated links for a specific node/pair of nodes. Hope I make sense
Any help truly appreciated.

Get node descendants in a tree graph

I have a directed graph (grafopri1fase1) the graph has no loops and it has a tree structure (not binary tree).
I have an array of nodes (meterdiretti) that i have extracted from the graph (grafopri1fase1) matching a condition.
I would like to know starting from each node of Meterdiretti how many nodes are under each node of Meterdiretti.
The result I would like to have is a Matrix with the following format
first column------------ second column
meterdiretti[1] -------- total amount of nodes reachable starting from meterdiretti[1]
meterdiretti[2] -------- total amount of nodes reachable starting from meterdiretti[2]
....
meterdiretti[n] ----------total amount of nodes reachable starting from meterdiretti[n]
Take a punt at what you want - it would be good if you could add a reproducible example to your question.
I think what you want is to count the descendents of a node. You can do this with neighborhood.size and mode="out" argument.
library(igraph)
# create a random graph
g <- graph.tree(17, children = 2)
plot(g, layout=layout.reingold.tilford)
# test on a single node
neighborhood.size( g, vcount(g), "1", "out") - 1
# [1] 16
# apply over a few nodes
neighborhood.size( g, vcount(g), c(1,4,7), "out") - 1
[1] 16 4 2

Query ArangoDB general-graph for common neighbors with more than 2 start vertices?

Consider the following example graph:
 
Given the vertices A, B and C (creators), how to figure out their common neighbors?(projects all 3 participated in)For two vertices, I could simply use GRAPH_COMMON_NEIGHBORS("myGraph", A, B), but what if I want to query for 3 or more? Expected result: 1 and 2.
Given the same vertices, how can I make it return common neighbors with no other connections?(creators exclusively participated in a project, no additional edges allowed)?Expected result: 1, because 2 has an edge coming from D, which isn't one of the starting vertices.
You can simply pass the same set of vertices as both parameters for common neighbors. Then repack the result in a better format for AQL to compute the intersection:
let res = (
let nodes = ["a/A","a/B","a/C"]
for n in GRAPH_COMMON_NEIGHBORS("g",nodes , nodes)
for f in VALUES(n)
return VALUES(f)
)
return CALL("intersection", res[0])

Generate directed lattice with equal number of neighbours for each node

I would like to generate a lattice with 100 nodes but would like to ensure that all nodes have the same number of neighbours.
However when I do:
d=graph.lattice(100,0,nei=10,directed=TRUE,circular=TRUE)
get.edgelist(d)
then I can see that many of the nodes do not have the same number of neighbours.
Is there any way to ensure that every node has the same number of connections assuming that the first column represents nodes and the second column connections?
This is because the default edge directions for graph.lattice are not the best for directed graphs. What you can do is creating an undirected graph, and then converting it to directed:
d <- as.directed(graph.lattice(100, 0, nei=10, directed=FALSE, circular=TRUE))
unique(degree(d, mode="in"))
# [1] 20
unique(degree(d, mode="out"))
# [1] 20
If you want non-mutual edges, then the easiest (but somewhat less readable) solutions is
d <- graph(sapply(1:100, function(i) {
rbind(i, ((i+1):(i+10)-1) %% 100 + 1)
}))
unique(degree(d, mode="in"))
# [1] 10
unique(degree(d, mode="out"))
# [1] 10
You can create a edgelist and make the graph from that. In that case, assuming that you only consider neighbors linked to (directed), then you could do something like:
el <- do.call(rbind,
lapply(1:100,
function(e) {cbind(rep(e,10),
sample(setdiff(1:100, e),10))}))
d <- graph.edgelist(el)
This picks 10 random nodes (other than itself) to link a node to.

How to copy a vertex with it's respective edges (all/in/out) from a directed graph g, to a new directed graph g1?

Is there a method or a class in igraph to do this procedure fast and efectively?
Let's assume that your graph is in g and the set of vertices to be used is in sampled (which is a vector consisting of zero-based vertex IDs).
First, we select the set of edges where at least one endpoint is in sampled:
all.vertices <- (1:vcount(g)) - 1
es <- E(g) [ sampled %--% 1:n ]
es is now an "edge sequence" object that consists of the edges of interest. Next, we take the edge list of the graph (which is an m x 2 matrix) and select the rows corresponding to the edges:
el <- get.edgelist(g)[as.vector(es)+1]
Here, as.vector(es) converts the edge sequence into a vector consisting of the edge IDs of the edges in the edge sequence, and use it to select the appropriate subset of the edge list. Note that we had to add 1 to the edge IDs because R vectors are indexed from 1 but igraph edge IDs are from zero.
Next, we construct the result from the edge list:
g1 <- graph(el, vcount(g), directed=is.directed(g))
Note that g1 will contain exactly as many vertices as g. You can take the subgraph consisting of the sampled vertices as follows:
g1 <- subgraph(g1, sampled)
Note to users of igraph 0.6 and above: igraph 0.6 will switch to 1-based indexing instead of 0-based, so there is no need to subtract 1 from all.vertices and there is no need to add 1 to as.vector(es). Furthermore, igraph 0.6 will contain a function called subgraph.edges, so one could simply use this:
g1 <- subgraph.edges(g, es)

Resources