Topological sort, but with a certain kind of grouping - algorithm

It seems this must be a common scheduling problem, but I don't see the solution or even what to call the problem. It's like a topological sort, but different....
Given some dependencies, say
A -> B -> D -- that is, A must come before B, which must come before D
A -> C -> D
there might be multiple solutions to a topological sort:
A, B, C, D
and A, C, B, D
are both solutions.
I need an algorithm that returns this:
(A) -> (B,C) -> (D)
That is, do A, then all of B and C, then you can do D. All the ambiguities or don't-cares are grouped.
I think algorithms such as those at Topological Sort with Grouping won't correctly handle cases like the following.
A -> B -> C -> D -> E
A - - - > M - - - > E
For this, the algorithm should return
(A) -> (B, C, D, M) -> (E)
This
A -> B -> D -> F
A -> C -> E -> F
should return
(A) -> (B, D, C, E) -> (F)
While this
A -> B -> D -> F
A -> C -> E -> F
C -> D
B -> E
should return
(A) -> (B, C) -> (D, E) -> (F)
And this
A -> B -> D -> F
A -> C -> E -> F
A -> L -> M -> F
C -> D
C -> M
B -> E
B -> M
L -> D
L -> E
should return
(A) -> (B, C, L) -> (D, E, M) -> (F)
Is there a name and a conventional solution to this problem? (And do the algorithms posted at Topological Sort with Grouping correctly handle this?)
Edit to answer requests for more examples:
A->B->C
A->C
should return
(A) -> (B) -> (C). That would be a straight topological sort.
And
A->B->D
A->C->D
A->D
should return
(A) -> (B, C) -> (D)
And
A->B->C
A->C
A->D
should return
(A) -> (B,C,D)

Let G be the transitive closure of the graph. Let G' be the undirected graph that results from removing the orientation from G and taking the complement. The connected components of the G' are the sets you are looking for.

Related

how to sort by levels in graphviz

I want to separate the rectangles like this
or (3 items per line)
You were quite close. Most of the changes are just for (my) clarity. rank=same and dir=back
// https://stackoverflow.com/questions/72449201/how-to-sort-by-levels-in-graphviz
digraph {
{rank=same; a -> b -> c}
{rank=same; edge [dir=back] f -> e -> d }
{rank=same; g -> h -> i}
{rank=same; edge [dir=back] l -> k -> j }
c -> d
f -> g
i->j
}
Giving:

Algorithm for grouping many singly linked lists

I have a data set that consists of objects with the form:
A -> Some parent (E.g. A -> null)
B -> Some parent (E.g. B -> D)
C -> Some parent (E.g. C -> A)
D -> Some parent (E.g. D -> null)
E -> Some parent (E.g. E -> A)
F -> Some parent (E.g. F -> G)
G -> Some parent (E.g. G -> D)
H -> Some parent (E.g. H -> C)
I -> Some parent (E.g. I -> G)
J -> Some parent (E.g. J -> null)
I want all the grouped linked lists, something like the following:
A <- C <- H
^-E
J
D <- B
^- G <- F
^- I
Is there a general algorithm to solve the problem of grouping the singly-linked lists that will perform better than pure brute force?
The use case for me here is that, given G, how can I get:
D <- B
^- G <- F
^- I
in an efficient way.
Construct an array of 2-element structures, in which the first element is the destination and the second is the source:
(null, A),
( D, B),
( A, C),
(null, D),
( A, E),
( G, F),
( D, G),
( C, H),
( G, I),
(null, J)
Sort this array by the first element:
(null, A),
(null, D),
(null, J),
( A, C),
( A, E),
( C, H),
( D, B),
( D, G),
( G, F),
( G, I)
And then recursively reveal the whole graph, using the initial data and the array just created:
a.
^- G
b.
^- G <- F
^- I
c. D
^- G <- F
^- I
d. D <- B
^- G <- F
^- I

Generating First Set from the grammar

Algorithm for Finding first set:
Given a grammar with the rules A1 → w1, ..., An → wn, we can compute the Fi(wi) and Fi(Ai) for every rule as follows:
initialize every Fi(Ai) with the empty set
set Fi(wi) to Fi(wi) for every rule Ai → wi, where Fi is defined as follows:
Fi(a w' ) = { a } for every terminal a
Fi(A w' ) = Fi(A) for every nonterminal A with ε not in Fi(A)
Fi(A w' ) = Fi(A) \ { ε } ∪ Fi(w' ) for every nonterminal A with ε in Fi(A)
Fi(ε) = { ε }
add Fi(wi) to Fi(Ai) for every rule Ai → wi
do steps 2 and 3 until all Fi sets stay the same.
Grammar:
A -> B C c
A -> g D B
B -> EPSILON | b C D E
C -> D a B | c a
D -> EPSILON | d D
E -> g A f | c
This website generates the first set as follows:
Non-Terminal Symbol First Set
A g, ε, b, a, c, d
B ε, b
C a, c, ε, d
D ε, d
E g, c
But the algorithm says Fi(A w' ) = Fi(A) for every nonterminal A with ε not in Fi(A) so the First(A) according to this algorithm should not contain ε. First(A) = {g, b, a, c, d}.
Q: First(A) for the above grammar is = First(B) - ε U First(C) U {g} ?
This video also follows the above algorithm and do not choose ε.
First(B) = {ε, b}
First(D) = {ε, d}
First(E) = {g, c}
First(C) = {c, d, a}
First(A) = {b, g, c, d, a}
Example:
X -> Y a | b
Y -> c | ε
First(X) = {c, a, b}
First(Y) = {c, ε}
First(X) doesn't have ε because if you replace Y by ε, then First(Y a) is equal to First(ε a) = {a}
First set implementation on my github.
Edit: Updated link
https://github.com/amirbawab/EasyCC-CPP/blob/master/src/syntax/grammar/Grammar.cpp#L229
Computing the first and follow sets are both available on the new link above.

How to use apply to "extract" a implication in Coq

I'll illustrate using an example.
H : R -> P -> Q
H0 : R
Subgoal:
(Q -> P) \ / (P -> Q)
so my question is how do I extract out (P->Q). I have R already, but when I do
'apply H in H0', it evaluates everything and gives me Q.
You can do any of:
specialize (H H0).
to replace H with H: P -> Q, or:
pose proof (H H0) as H1
to introduce H1: P -> Q
You can also go forward:
right. exact (H H0).

Graphviz Dot vertical alignment of nodes

I got this dot graph and want the nodes A and D, B and E and C and F to be aligned. Here is the related dot code:
digraph{
A
B
C
D
E
F
{rank = same; B; C}
{rank = same; E; F}
A -> B [label="2", weight=2]
A -> C [label="0", style=dashed, weight=2]
B -> C [label="0", style=dashed, weight=2]
B -> D [label="2", style=dashed, weight=2]
C -> D [label="0", weight=2]
D -> E [label="1", style=dashed, weight=2]
D -> F [label="0", weight=2]
E -> F [label="0", weight=2]
F -> A
}
As you can see I already tried to apply weights to the edges, but that didn't work out
It is possible to use the group attribute of the nodes to suggest aligning the edges between nodes of the same group in a straight line.
Declare the nodes with the group attribute:
A [group=g1]
{rank = same; B[group=g2]; C[group=g3]}
D [group=g1]
{rank = same; E[group=g2]; F[group=g3]}
Then make sure all of those nodes have an (invisible) edge between them:
edge[style=invis];
A -> D
B -> E
C -> F
Everything together:
digraph G {
A [group=g1]
{rank = same; B[group=g2]; C[group=g3]}
D [group=g1]
{rank = same; E[group=g2]; F[group=g3]}
A -> B [label="2", weight=2]
A -> C [label="0", style=dashed, weight=2]
B -> C [label="0", style=dashed, weight=2]
B -> D [label="2", style=dashed, weight=2]
C -> D [label="0", weight=2]
D -> E [label="1", style=dashed, weight=2]
D -> F [label="0", weight=2]
E -> F [label="0", weight=2]
F -> A
edge[style=invis];
A -> D
B -> E
C -> F
}

Resources