How to go from an edge list or adjacency list representation of a planar graph to a face list?
For example, with this graph (which is not 0-indexed, oddly enough):
I'd want a list that looks something like this:
[
[1,2,8,7],
[1,2,4,3],
[1,3,5,7],
[2,4,6,8],
[5,6,7,8],
[3,4,6],
[3,5,6]
]
It wouldn't have to be in that format or order, but it should be some kind of list (or set) of all faces. The outer face is included.
For a graph with V vertices (E=O(V) because planar), the algorithm should generate this list in O(V).
You need to generate a planar embedding of the graph. One issue is that often a biconnected graph can generate multiple planar embeddings.
One planarity testing and embedding algorithm is given in the "Planarity Testing by Path Addition" PhD thesis and this solves the problem of generating all possible planar embeddings of a graph (in O(V+E) time and memory for a single embedding for a biconnected graph with V vertices and E edges, and in O(P(V+E)) time and O(V+E) memory to generate all possible unique planar embeddings, where P is the number of permutations of embeddings).
Chapter 5 details the algorithm needed to test a graph for planarity and then to generate a cyclic edge order for each vertex (and also how to iterate to the next permutation of the embedding).
Given a cyclic edge order, you can generate the faces of the graph by taking each edge and following the next clockwise (or anti-clockwise) edge in the cyclic edge ordering as you come to each successive vertex.
The short answer is : you have to actually layout the graph! More exactly, you have to find an embedding of the graph in the plane - assuming that there is one without edge crossings.
So, your embedding above is :
1: [2, 7, 3]
2: [1, 4, 8]
3: [1, 5, 6, 4]
...
which is each vertex with an ordering on its neighbour set. You have to specify if that ordering is clockwise or anti-clockwise, but otherwise that should be all.
Once you have the embedding, it is possible to recover the faces using a combinatorial map. This looks trickier than it really is, although it does involve darts (or flags).
First, break each edge into flags (vertex + half-edge) and make a permutation (sigma in the wiki description) that stores the map. For example, we could label the flags in the same order as the map - then 1: [2, 7, 3] becomes {1->2 : 1, 1->7 : 2, 1->3 : 3} and so on.
For example, a cube (note : removed the middle edge!):
Then calculate alpha (the involution permutation) which just maps flags to the other flag across the edge. Finally, phi is the product of these two permutations, and the cycles of phi gives you the faces.
So, from the phi in the image, we have (1, 6, 24, 19) which is the outer face (note that these are darts, so we consider the vertex it starts from).
As #gilleain mentioned in his answer, you have to actually layout the graph, as there could be multiple layouts if you just give the topology. Here I'll give some algorithmic analysis and then a straightforward solution.
Lemma 1: An edge is involved in at least one face, and at most two
faces.
Proof: We're drawing in 2D space so a line splits a plane into two halves.
This means that we can attach a "capacity" to each of the edges, initialized to 2. When we find an face involving an edge, we subtract 1 from it.
As a face is a loop in the planar graph, the problem turns to find loops given the aforementioned constraint.
Lemma 2: If we examine the difference between two valid solutions, they differ in edges that have complementary capacities (1 vs. 2 and 2 vs. 1).
Proof: See the figure.
As a consequence, when you drain the capacity for an edge when finding a solution, you automatically exclude the ambiguity that leads to another solution.
So the straightforward solution is to conduct DFS in the graph to find loops. When you find one, subtract the capacities of the involved edges. When the capacity reaches 0, consider the edge removed when DFS further. Note, when a loop is found, we must check if all the edges within have capacity 1. If so, then this loop must be skipped, as including this loop into our result leads to repeated counting.
def DFS-Tarjan(v, capacities, stack)
for e in N(v):
if capacity[e] != 0:
if stack.contains[e.target] AND NOT all of them have capacity 1:
output-loop(stack, e.target)
for e2 in stack:
capacity[e2] -= 1
else:
stack.push(e.target)
DFS-Tarjan(v, capacities, stack)
stack.pop(e.target)
else:
pass # capacity drained
def find-faces(g):
initialize capacities of g.E to [2...2]
for v in unvisited(g.V):
DFS-Tarjan(v, capacities, [])
Multiple solutions can be found if you alter the order for DFS. For a single solution, the algorithm is O(V) as each edge is consumed no more than twice.
Related
I've been reading some papers on multicut algorithms for segmenting graph structures. I'm specifically interested in this work which proposes an algorithm to solve an extension of the multicut problem:
https://www.cv-foundation.org/openaccess/content_iccv_2015/papers/Keuper_Efficient_Decomposition_of_ICCV_2015_paper.pdf
Regarding the edge costs, it says:
...for any pair
of nodes, a real-valued cost (reward) to all decompositions
for which these nodes are in distinct components
Fair enough. It further says that the solution to the multicut problem is a simple binary vector of length equal to the number of edges in the graph, in which a '1' indicates that the corresponding edge separates two vertices belonging to distinct graph components:
for every edge vw ∈ E ∪ F , y(v,w) = 1 if and only if v and w
are in distinct components of G.
But then the optimization problem is written as:
This doesn't seem to make sense. If the edge weights depict rewards for that edge connecting nodes in distinct components, shouldn't this be a maximization problem? And in either case, if all edge weights are positive, wouldn't that lead to a trivial solution where y is an all-zeros vector? The above expression is followed by some constraints in the paper, but I couldn't figure out how any of those prevent this outcome.
Furthermore, when it later tries to generate an initial solution using Greedy Additive Edge Contraction, it says:
Alg. 1 starts from the decomposition into
single nodes. In every iteration, a pair of neighboring components is joined for which the join decreases the objective
value maximally. If no join strictly decreases the objective
value, the algorithm terminates.
Again, if edge weights are rewards for keeping nodes separate, wouldn't joining any two nodes reduce the reward? And even if I assume for a second that edge weights are penalties for keeping nodes separate, wouldn't this method simply lump all the nodes into a single component?
The only way I see where this would work is if the edge weights are a balanced combination of positive and negative values, but I'm pretty sure I'm missing something because this constraint isn't mentioned anywhere in literature.
Just citing this multicut lecture
Minimum Multicut. The input consists of a weighted, undirected graph G
= (V,E) with a non-negative weight c_k for every edge in E, and a set of terminal pairs {(s1,t1);(s2,t2)...(sk,tk)}. A multicut is a set of
edges whose removal disconnects each of the terminal pairs.
I think from this definition it is clear that the multicut problem is a minimization problem for the accumulated weight which is defined by the selection of edges to cut. Maximizing the weight would of course be trivial (removing all edges). No?
Better late than never, here's the answer:
The weights c_e for cutting the edge e are not restricted to be positive as defined in Definition 1. In fact, Equation (7) specifies that they are log-ratios of two complementary probabilities. That means if the estimated probability for edge e being cut is greater than 0.5, then c_e will be negative. If it's smaller, then c_e will be positive.
While the trivial "all edges cut" solution is still feasible, it is quite unlikely that it is also optimal in any "non-toy" instance where you will have edges that are more likely to be cut while others are more likely to remain.
I am reading Introduction to Algorithms. In 22.5 Strongly Connected Component, the algorithm STRONGLY-CONNECTED-COMPONENT(G) is defined as:
Call DFS(G) to compute finishing times u.f for each vertex u
Compute G transpose
Call DFS(G transpose), but in the main loop of DFS, consider the vertices in order of decreasing u.f(as computed in line 1)
Output the vertices of each tree in the depth-first forest formed in line 3 as a separate strongly connected component
If I change the alogrithm to just using G, without calculating G transpose. Also consider the vertices in order of Increasing u.f(Reverse order of topological sort):
Call DFS(G) to compute finishing times u.f for each vertex u
Call DFS(G), but in the main loop of DFS, consider the vertices in order of increasing u.f(as computed in line 1)
Output the vertices of each tree in the depth-first forest formed in line 2
Why is this algorithm wrong?
Your question is actually exercise 22.5-3 in the book. A counter example to the correctness of your alternative algorithm is given here:
http://sites.math.rutgers.edu/~ajl213/CLRS/Ch22.pdf
Professor Bacon’s suggestion doesn’t work out. As an example, suppose that
our graph is on the three vertices {1, 2, 3} and consists of the edges (2, 1),(2, 3),(3, 2).
Then, we should end up with {2, 3} and {1} as our SCC’s. However, a possible
DFS starting at 2 could explore 3 before 1, this would mean that the finish
time of 3 is lower than of 1 and 2. This means that when we first perform the
DFS starting at 3. However, a DFS starting at 3 will be able to reach all other
vertices. This means that the algorithm would return that the entire graph is a
single SCC, even though this is clearly not the case since there is neither a path
from 1 to 2 of from 1 to 3.
The vertices in strongly connected component are, by definiton, connected to each other (by a path, not necessarily by direct edge). if you make first DFS call on vertex X, you find out "which vertices is X connected to" (X -> N). To make sure that all those vertices are connected to X (N -> X) and therefore validate strong connectivity you need to traverse the edges in reversed directions. The easiest way to do such is by transposing the graph.
If you look for proof of the algorithm, i am sure you will find some. It may not be the easiest to understand but check this source for example:
Correctness of the algorithm for finding strongly connected components
Background:
As you can see below, there is an undirected graph on the left of the figure. Vertices are represented by S1,S2 ... S6, and edges are represented by line segments between vertices. Every edge has a weight (the number near the edge), either positive or negative.
Definitions:
In the graph, a simple cycle is called a conflicting cycle if it has an odd number of negative edges, and a concordant cycle if an even (or zero) number of negative edges. On the left of the figure below, for example, the graph has two conflicting cycles(S1-S2-S3-S1 and S2-S3-S4-S2), and other cycles are concordant. A graph is called happy if it has no conflicting cycle.
Objective:
Make the graph happy by removing some edges, meanwhile ensuring the cost(the sum of absolute values of weights of removed edges) is lowest. In the figure below, for example, after removing the edge (red line segment), there is no conflicting cycles. So the graph becomes happy, and the cost is only 2.
This problem is NP-hard by reduction from maximum cut. Given an instance of maximum cut, multiply all of the edge weights by -1. The constraints of this problem dictate that edges be removed so as to eliminate all odd cycles, i.e., we need to find the maximum-weight bipartite subgraph.
This problem in fact is equivalent to a 2-label unique label cover problem. The goal is to color each vertex black or white so as to minimize the sum of costs for (i) positive edges that connect vertices of different colors (ii) negative edges that connect vertices of the same color. Deleting all of these edges is a valid solution to the original problem. Conversely, given a valid set of edges to delete, we can determine a coloring. I expect that there's an approximation algorithm based on semidefinite programming (and the relaxation could be used for branch and bound).
Unless you're familiar with combinatorial optimization, however, the algorithm that I would suggest is integer programming. Let x(e) be 1 if we delete edge e and let x(e) be 0 if we don't.
minimize sum_{edges e} cost(e) x(e)
subject to
for every simple cycle C with an odd number of negative edges,
sum_{edges e in C} x(e) >= 1
for each edge e, x(e) in {0, 1}
The solver will do most of the work. The problem is handling the exponential number of constraints that I've written. The crudest thing to do is to generate all simple cycles and give the solver the whole program. Another possibility is to solve to optimality with a subset of the constraints, test whether the solution is actually valid, and, if not, introduce one or more missing constraints. To do the test, attempt to two-color the undeleted subgraph such that vertices joined by a positive edge have identical colors and vertices joined by a negative edge have different colors. Color greedily; if we get stuck, then there's an odd cycle at fault.
With more sophistication, it's possible to solve the program as written via a technique called column generation.
I've written a solver for this problem (under the name "Signed Graph Balancing"). It is based on a fixed-parameter algorithm that is fast if only few edges need to be deleted. The method is described in the paper "Separator-based data reduction for signed graph balancing".
I'm trying to generate an undirected graph in which each node has a maximum degree associated with it. That is, if a node has a maximum degree of 2, it can connect to at most two nodes (connected node would be allowed, but not 0). My problem is that I'm trying to generate a graph in which its possible to get from one node to the other. Currently, I can have nodes "randomly" connect to one other, but the problem is that its possible to create divided graphs, ie if you have 10 nodes, then sometimes inadvertently two graphs of 5 nodes each forms. If anyone knows of an efficient solution, I'd love to hear it!
EDIT: Suppose that I have a graph with ten nodes, and I specify a maximum degree of 2. In this case, here is something that would be desirable:
Whereas this is what I'm trying to avoid:
Both graphs have a maximum degree of 2 per node, but in the second image, it's not possible to select an arbitrary node and be able to get to any other arbitrary node.
This problem is a pretty well-known problem in graph theory, soluble in polynomial time, the name of which I forget (which is probably "find a graph given its degree sequence"). Anyhow, Király's solution is a nice way to do it, explained much better here than by me. This algorithm solves for the exact graphs that satisfy the given degree sequence, but it should be easy to modify for your more loose constraints.
The obvious solution would be to build it as an N-way tree -- if the maximum degree is two, you end up with a binary tree.
To make it undirected, you'll have pointers not only to the "child" nodes, but also a backward pointer to the "parent" node. At least presumably, that one doesn't count toward the degree of the node (if it does, your degree of two basically ends up as a doubly-linked linear list instead of a tree).
Edit: post-clarification, it appears that the latter really is the case. Although they're drawn different (with links going in various different directions) your first picture showing the desired result is topologically just a linear linked list. As noted above, since you want an undirected graph, it ends up as a doubly linked list.
It sounds like you already know what the graph should look like, so I believe if you can use a depth-first search approach. Although breath-first search can be used to avoid recursion.
For example, if you have the nodes 1-5, and k=2, then you can build a graph by starting at node 1, and then simply randomly choosing an unvisited node. Like so:
1 [Start at 1]
1-2 [expand 2, add edge(1,2) to graph]
1-2-3 [expand 3, add edge(2,3) to graph]
1-2-3-4 [expand 4, add edge(3,4) to graph]
1-2-3-4-5 [expand 5, add edge(4,5) to graph]
1-2-3-4-5-1 [expand 1, add edge(5,1) to graph] (this step may or may not be done)
If an edge is never used twice, then p paths will lead to degree p*2 overall, with the degree of the start and end nodes dependent on if the paths are really a tour. To avoid duplicate work, it is probably easier to just label of the vertices as the integers 1 through N, then create edges such that each vertex, v, connects to the vertex numbered (v+j) mod (N+1) where j and (N+1) are co-prime < N-1. The last bit making things a bit problematic, as the number of co-primes from 1 to N can be limited if N is not prime. This means solutions don't exist for certain values, at least in the form of a new Hamiltonian path/tour. However, if you ignore the co-prime aspect and simply make j be integers from 1 thru p, then go through each vertex and create the edges (instead of using the path approach), you can make all the vertices have degree k, where k is an even number >= 2. This is achievable in O(N*k), although it may be pushed back as far as O(N^2) if co-prime method is used.
Thus the path for k=4 would look like this, if started at 1, with j=2:
1 [Start at 1]
1-3 [expand 3, add edge(1,3) to graph]
1-3-5 [expand 5, add edge(3,5) to graph]
1-3-5-2 [expand 2, add edge(5,2) to graph]
1-3-5-2-4 [expand 4, add edge(2,4) to graph]
1-3-5-2-4-1 [expand 1, add edge(4,1) to graph] (this step may or may not be done)
Since |V| = 5 and k = 4, the resulting edges form a complete graph, which is expected. It's also works out since 2 and 5 are co-prime.
Obtaining an odd degree is a bit more difficult. First obtain the degree k-1, then edges are added in such a way an odd degree is obtained overall. It seems fairly easy to get very close (with one or two exceptions) to all edges being an odd degree, but it seems impossible or at least very difficult with odd number of vertices, and requires a careful selection of edges with even number of vertices. The section of which, isn't easy to put into an algorithm. However, it can be approximated by simply picking two unused vertices and creating an edge between them such that the vertices are not used twice, and the edges are not used twice.
In Graph, there is a triangular strip problem. Basically, we have a set of adjacent triangles and we want to consider each triangle as a new vertex and there will be an edge between two new vertices if the two triangles behind them have an edge in common.
My question here is about reading each triangle and construct the new strip graph for them.
For example, we have these triangles (A, B and C):
A - 0, 1, 3
B - 1, 2, 3
C - 2, 3, 4
so A and B have a common edge and so do B and C. the new strip go from A to B and then to C.
Ok. I think one of the key things here is that each time when you read a new triangle, we want to know which triangles have common edges with the new one.
A stupid way is that we just scan all old triangles and compare their three vertices with the new one's vertices, and if two vertices match, then there is a adjacency.
A better way (described in The Algorithm Design Manual) is that each time when we create a list for each triangle vertex. That list contains all triangles that pass through the vertex. for example, for the triangles above, vertex 0 has the list of {A}, vertex 1 has the list of {A, B}, etc. So when a new triangle comes, we just need to check 3 vertices and try to find which old triangles having two common vertices with the new one.
Here comes some questions:
Is the better way linear? How to define the "linear" for this kind of reading and constructing graph? For example, in the better way, a new triangle need to go through 3 lists of old triangles. Is this linear enough? I thought it is linear because at most it just read all old triangles. But if my thought is true, then the stupid way is also linear, right? so I guess I may be wrong, but very confused.
Will there be a even better way? This is asked by Algorithm Design Manual as an excise and that excise asks for a pure linear algorithm even in worst case.
My solution for a even better way is that instead of build a list for each vertex, I build a list for each edge. A vertex can have many triangles passing through, but with an edge, there will be at most two triangles passing assuming that all triangles' edges are not crossing each other and at most merge (in common).
Then each edge has a list of at most two items. and for a newly coming triangle, it need to check at most 3 edges. I think it is better than the better way above.
Am I right? or Is my better better way a pure best linear solution?
Is the better way linear?
No, it is not. As you say, yes there will be three lists to examine which is a much more smaller space than the whole old triangles as the Stupid Way does, but the length of these lists are growing, again linearly as the number of triangles examined grows. In the worst case, the better way has the same complexity as the stupid way which is polynomial (the case where all triangles share a vertex)
A - 0, 1, 2
B - 0, 2, 3
C - 0, 3, 4
D - 0, 4, 5
...
About your solution to this problem, you are right, yours is a linear one assuming fetching an edge from the previously created edges is done in constant time (a hashtable like structure is required, not a list).
Moreover, you can improve yours as just remembering the edges that have been added to the list (hashtable?) once, and removing those that are encountered twice (since it is assumed that an edge can only be shared between two triangles)