Singly connected Graph? - graph-algorithm

A singly connected graph is a directed graph which has at most 1 path from u to v ∀ u,v.
I have thought of the following solution:
Run DFS from any vertex.
Now run DFS again but this time starting from the vertices in order of decreasing finish time. Run this DFS only for vertices which are not visited in some previous DFS. If we find a cross edge in the same component or a forward edge, then it is not Singly connected.
If all vertices are finished and no such cross of forward edges, then singly connected.
O(V+E)
Is this right? Or is there a better solution.
Update : atmost 1 simple path.

A graph is not singly connected if one of the two following conditions satisfies:
In the same component, when you do the DFS, you get a road from a vertex to another vertex that has already finished it's search (when it is marked BLACK)
When a node points to >=2 vertices from another component, if the 2 vertices have a connection then it is not singly connected. But this would require you to keep a depth-first forest.

A singly connected component is any directed graph belonging to the same entity.
It may not necessarily be a DAG and can contain a mixture of cycles.
Every node has atleast some link(in-coming or out-going) with atleast one node for every node in the same component.
All we need to do is to check whether such a link exists for the same component.
Singly Connected Component could be computed as follows:
Convert the graph into its undirected equivalent
Run DFS and set the common leader of each node
Run an iteration over all nodes.
If all the nodes have the same common leader, the undirected version of the graph is singly connected.
Else, it contains of multiple singly connected subgraphs represented by their corresponding leaders.

Is this right?
No, it's not right. Considering the following graph which is not singly connected. The first component comes from a dfs beginning with vertex b and the second component comes from a dfs beginning with vertex a.
The right one:
Do the DFS, the graph is singly connected if all of the three following conditions satisfies:
no foward edges
no cross edges in the same component
there is no more than 1 cross edges between any two of components

Related

Graph: Creating shortest marked path to connect two nodes

Given an undirected, unweighted graph in which some nodes are marked, is there an efficient way to find the unmarked nodes between node A and B which would create a "marked" path from A to B when they are marked? The number of those "bridge" nodes should be minimal.
For example, in the graph below there would be two minimal ways to connect node A to B. One possibility would be to mark the node labelled 1, the other possibility would be to mark node 2.
Convert your graph into a directed, weighted graph such that:
the weight of each edge going into a marked node is set to 0
the weight of each edge going into an unmarked node is 1
Find all lowest-cost paths from A to B.

How does the Minimum spanning tree in neo4j work

I am playing around with some graph theory algorithms in neo4j. I am trying to find the minimum spanning tree (mst) within my network. I synthetically created a network of 10 000 people. Each person has 12 relationship types each one linking him back to the other 9999 and each relationship with its own weight assigned.
The problem I have however is the fact that according to the definition the results must be a tree spanning over the ENTIRE network. The neo4j function however only returns a very small sub-graph (only about 12 nodes) of the entire network.
The code I am using looks like this:
MATCH (a:Name {Name:"Dillon Snow"})
CALL algo.mst(a,"Weight",{stats:true})
YIELD loadMillis, computeMillis, writeMillis, weightSum, weightMin, weightMax, relationshipCount
RETURN loadMillis, computeMillis, writeMillis, weightSum, weightMin, weightMax, relationshipCount
What can I change to get the function to return the mst spreading through the entire network
algo.mst.* has not been adapted to the matured Neo4j-Graph-Algorithms-CoreAPI in its current release (3.2.5.2/3.3.0.0 # Dec 2017) which might lead to unexpected results. But there is a pull request in the pipe, you can expect some changes in the next release.
Anyway.. The procedure should add a new relationship-type (default mst) to your nodes. In a connected graph each node should be connected as well while a disconnected graph leads to connections only between the nodes of this particular connected component (from your startNode).
If i understand you right you have multiple relationship types and more then one of them between a pair of nodes? E.g. Node A is connected to Node B with several relations, each of them with a different type and property value. This is a problem. In general the Graph-Algorithms-API does not support multible releationships. Each pair of nodes can only have one connection per direction. Although you can import multible types the core-api itself has no idea of the underlying type. If multible relationships between a pair of nodes get imported usualy the last one wins. This has been mentioned in the documentation ;)
To overcome this limitation you could replace your relationship types with some kind of artificial nodes. When traversing over the result tree the occurence of one of those nodes would indicate the original relationship.

Find all nodes with two-way relationships starting from one specific node using cypher in neo4j

neo4j nodes and relationships
This is quite a tough job. I'm trying to find all nodes with two-way relationships starting from a specific node. Based on the image above, I would like to find all two-way relationships starting from node 1. Only nodes with two-way relationships match. For example, node 1,3,4 matches and node 1,2,3 matches as two separate groups. However, if node 2 and 4 has a two-way relationship, then node 1,2,3,4 matches as one group. The main idea is that all nodes are linked both ways in such a group. My idea is to find all nodes with two-way relationships starting from 1 and continue processing, but I'm not able to continue. Can anyone help me with this problem, thanks a lot. By the way, only the largest 'two-way-circle' is needed.
Your problem looks a lot like finding strongly connected components in the graph. As defined in the docs.
A directed graph is strongly connected if there is a path between all
pairs of vertices ( nodes ). This algorithms treats the graph as directed, so
the direction of the relationship is important and strongly connected
compoment exists only if there are relationships between nodes in both
direction.
Check out more in the documentation. You will need neo4j-graph-algorithms.
Example query with writing back the component of the graph to the node.
CALL algo.scc('Label','C', {write:true,partitionProperty:'partition'})
YIELD loadMillis, computeMillis, writeMillis, setCount, maxSetSize, minSetSize
And then you can find your biggest component with the following query.
MATCH (u:Label)
RETURN distinct(u.partition) as partition,count(*) as size_of_partition
ORDER by size_of_partition DESC LIMIT 1

Using cypher or traversal api to match only a single node on extreme sides of a path

Say I have following path in the graph:
(:Type1)<-[:RelType1]-(:Type2)<-[:RelType2]-()<-[*]-(centernode)-[*]->()-[:RelType2]->(:Type2)-[:RelType1]->(:Type1)
Given <id> of (:Type1) node on left side, I am able to MATCH above path and get corresponding (:Type1) node on right side (notice that the path is symmetric and its center is node (centernode)). In my usecase we get <id>s of (:Type1) node, get the corresponding (:Type1) node on the other side and then process further.
However it may happen that I get <id>s of both nodes of (:Type1). In that case separate queries will be fired starting at corresponding node and will evaluate to the (:Type1) node on the other side, thus further execution will continue on both the nodes.
Q1. How can I avoid processing both nodes. That is, if given two <id>s of (:Type1) nodes which reside on extreme sides of same path, how can I ensure only one of the queries starting at one of these nodes matching node on the other side is executed so that only one of those nodes are processed further and other node is say held in temporary buffer to process afterwards (if processing of first node fails).
Added fact: Above I have a single path with two (:Type1) nodes at its extreme sides. I may have three or more paths emanating from (centernode) and ending in (:Type1) node. So I want only one of those (:Type1) nodes to get processed first, and next (:Type1) node will processed only if earlier processing fails.
Q2. Is this scenario even possible with pure cypher? Or I have to end up using Neo4J Traversal API? If yes how this can be done, as I have to ensure uniqueness of nodes/relationships visited across two different traveresals.
Q3. How can I add path expander in Traversal API to match path of type (:Type1)<-[:RelType1]-(:Type2)<-[:RelType2]-(). Should I be doing something like this:
at each traversal `next()`
if (node is of Type1)
follow <-[:RelType1]-
if (node is of Type2)
follow <-[:RelType2]-
(Above is pseudocode. I am new to Traversal API. I have went through all docs and examples. So I am guessing inside expander I have to put if() filters to check current nodes type and decide which relation type and its direction to expand next. Above pseudocode is meant to indicate that.)
Is this how such cypher can be writting in Traversal API? Or is there any better way?
An old trick is to use node ids to order pairs (ID(a) < ID(b)), which filters out "duplicate" results. So if you feed all your source IDs into a single query, you can make use this trick to filter out duplicates:
WITH [1, 2, 3, 4] AS sourceIds
UNWIND sourceIds AS sourceId
MATCH (source:Type1)
WHERE ID(source) = sourceId
MATCH
(source)<-[:RelType1]-(:Type2)<-[:RelType2]-
()<-[*]-(centernode)-[*]->()
-[:RelType2]->(:Type2)-[:RelType1]->(target:Type1)
WHERE ID(source) < ID(target)
RETURN source, target
Could this work for your use case?

How BFS can from a tree on certain directed graph?

It is said said BFS always gives a tree, while DFS gives a forest.
But I do not understand how BFS can always give a tree.
Consider this graph and starting point b
How do we get a tree here?
Don't understand why you have a directed graph and an terminal starting point b.
From b, it can go nowhere but stay at b.
If it not directed, then it will be b->a->c->d, no matter it is BFS or DFS.
First time heard DFS returns a forest. Guess people think this because every time it reaches end it will return to parent node.
A tree is basically a connected graph(at least one path between every pair of nodes) with no cycles.
If we do BFS on a connected graph, we will visit every node in the graph and each node is visited only once. So, there is only one path from starting node to every node we visit, since we visit it only once. There is also only one path between any pair of nodes by same argument as above (it will make more sense if you imagine a graph and comprehend). So, there are no cycles and hence it's a tree.
BFS not gives a tree. It use queue ,in fact. And alongside with DFS, BFS is also an algorithm to go through the tree.

Resources