8

As a personal easter project I'm trying to implement some model-based testing at work. I've got a graph implemented in python and I need to traverse all edges / do all transitions of the graph, at least once. Traversing an edge twice or more does not matter, but I need to start and end in the same node and get a sequence of edges/transitions back.

Simpler algorithm > shortest sequence.

I've looked around and found a lot of algorithms, but I couldn't find one / a combination that works for me. It would be great if someone could point me in the right direction or give me some tips on how to do this.

My graph implementation looks like this:

graph = {
    A : {'IDLE': 't8', 'B': 't2', 'C': 't4'},
    B : {'A': 't3', 'C': 't4', 'IDLE': 't6'},
    C : {'A': 't5', 'IDLE': 't7', 'B': 't2'},
    IDLE : {'A': 't1'}
}

graph

kristus
  • 447
  • 3
  • 7
  • 11
  • 1
    Your graph looks directed. Are you only allowed to traverse following the arrows? – Oliver Charlesworth Apr 06 '12 at 11:54
  • 1
    Well, this is the travelling salesman problem, isn't it. If you find a solution please do let the world know. – Daniel Roseman Apr 06 '12 at 11:54
  • Can we assume that your graph is [strongly connected](http://en.wikipedia.org/wiki/Strongly_connected_component)? – Mark Byers Apr 06 '12 at 11:55
  • 2
    @DanielRoseman: Actually it is Euler Cycle. TSP deals with visiting all nodes, not all edges. – Avaris Apr 06 '12 at 11:58
  • 1
    @Avaris: Actually it's not Euler cycle because you are allowed to visit edges more than once. The OPs requirement is that each edge is visited *at least* once. – Mark Byers Apr 06 '12 at 12:00
  • @MarkByers: Well, correct. It is more relaxed than the Euler Cycle. – Avaris Apr 06 '12 at 12:07
  • @OliCharlesworth Yes, directed is probably correct. I can only traverse following the arrow. – kristus Apr 06 '12 at 12:27
  • @MarkByers ...scratch that... The actual graph is about 5-10 times bigger. Would that have made it easier? – kristus Apr 06 '12 at 12:30
  • @kritus: If the graph is not strongly connected, it is not necessarily possible to visit every edge at least once and then return to your starting point. You can get stuck in a strongly connected component. They are sort of like black holes. Once you enter them, there's no way to get out again. – Mark Byers Apr 06 '12 at 12:32
  • @MarkByers Ah... My mistake. (Read it as each node had an edge to every other node.) Every node has "a way out" and you can't get stuck anywhere. – kristus Apr 06 '12 at 12:36

4 Answers4

5

Approach 1

You can change your graph G into a new graph G' where each edge in G becomes a node in G'. Make an edge from t1 to t2 in G' if "A -> t1 -> B -> t2 -> C" is possible in G for some A,B and C.

Then you need to find a path cover in G'.

Approach 2

  • Your position P initially is some node P0 (e.g. idle).
  • For each edge T (from A to B), find any route from P to A, then use T to go to B. Update P to be B.
  • Finally find any route from P back to P0.
Mark Byers
  • 811,555
  • 193
  • 1,581
  • 1,452
4

This problem is not the same as the Traveling Salesman Problem. Instead it's called a Chinese Postman Problem. The biggest difference is that the TSP wants to visit all nodes (cities) where the CPP wants to visit all edges (streets).

A perfect tutorial for exactly this can be found here: https://www.datacamp.com/community/tutorials/networkx-python-graph-tutorial

1

for each P1, P2 points in your graph find all the R roads, where R looks like this:

R = (P1, Pf1, ..., Pfn, P2)

for each R1, R2 roads from P1 to P2, if Intersection(R1, R2) has more than 0 points (except P1 and P2, of course) determine which is shorter. If the length of R1 is smaller than the length of R2 then forget R2, otherwise forget R1.

In an iteration you will find the shortest totally separate roads from P1 to P2. If you want to traverse a road, where you have the points (P1, ..., Pk) If we choose Pi, where 1<= i <= k, we know that the first point will be Pi and the last point will also be Pi.

Suppose that the order doesn't matter. Whenever you traverse a point, mark it as traversed. If a point is marked as traversed, you won't want to go again to the given point, but you won't mind traversing the point again if necessary. So, the planned road will be: Pf1, ..., Pfk, Pf1.

for each Pfj, Pfm:

We are in Pfj in this moment. If Pfm is traversed then we don't want to go to Pfm again, so we go to the next iteration

If Pfm is not traversed, we have R1, ..., Rq roads from Pfj to Pfm. Choose the road with the maximum number of untraversed points and minimum number of already traversed roads. You need to weight the importance of an untraversed Point in the road and a traversed Point by a clever idea (hopefully your weight will minimize the total length of your road from Pf1 to Pf1).

Note that Pf1 should not be marked as traversed, because you want to arrive there at the end of your algorithm.

Lajos Arpad
  • 64,414
  • 37
  • 100
  • 175
0

I am not sure if you want an algorithm or you want to know how to get your job done. If its the later, you can use networkx.

Once you downloaded and installed networkx you can try the following

>>> import networkx as nx
>>> DG=nx.DiGraph()
>>> def CycleFrom(G,node):
    return sorted((c for c in nx.simple_cycles(DG) if node in c), key=len)[0]

>>> for (stnode, edges) in graph.items():
    for (ennode,edge) in edges.items():
        DG.add_edge(stnode,ennode,name=edge)


>>> for node in DG.nodes():
    print "Cycles from {0} is {1}".format(node,CycleFrom(DG,node))


Cycles from A is ['A', 'IDLE', 'A']
Cycles from IDLE is ['A', 'IDLE', 'A']
Cycles from B is ['A', 'B', 'A']
Cycles from C is ['A', 'C', 'A']
>>> 
Abhijit
  • 62,056
  • 18
  • 131
  • 204