Finding the path in a graph from A to B then back to A with a minimum of shared edges The 2019 Stack Overflow Developer Survey Results Are In Announcing the arrival of Valued Associate #679: Cesar Manara Planned maintenance scheduled April 17/18, 2019 at 00:00UTC (8:00pm US/Eastern)Finding a “not-shortest” path between two verticesFinding all shortest paths between two verticesMaking FindShortestPath a little bit sloppyFinding all simple paths between two vertices in a graphGraphPath: *all* shortest paths for 2 vertices, edge lengths negativeFinding Hamiltonian path in GraphTest if directed graph is connectedHow do I get all possible paths in terms of edges, and not vertices in Mathematica?How to find the shortest path between specified verticesCompleting graph edges “around the world” to GeoPlot an itinerary

Create an outline of font

Didn't get enough time to take a Coding Test - what to do now?

Can withdrawing asylum be illegal?

Are my PIs rude or am I just being too sensitive?

University's motivation for having tenure-track positions

How to grep and cut numbes from a file and sum them

What aspect of planet Earth must be changed to prevent the industrial revolution?

The variadic template constructor of my class cannot modify my class members, why is that so?

Is a pteranodon too powerful as a beast companion for a beast master?

How to prevent selfdestruct from another contract

Why can't devices on different VLANs, but on the same subnet, communicate?

Change bounding box of math glyphs in LuaTeX

Semisimplicity of the category of coherent sheaves?

Typeface like Times New Roman but with "tied" percent sign

Can a 1st-level character have an ability score above 18?

How are presidential pardons supposed to be used?

How many people can fit inside Mordenkainen's Magnificent Mansion?

Is it ok to offer lower paid work as a trial period before negotiating for a full-time job?

Why use ultrasound for medical imaging?

Would it be possible to rearrange a dragon's flight muscle to somewhat circumvent the square-cube law?

Can smartphones with the same camera sensor have different image quality?

What are these Gizmos at Izaña Atmospheric Research Center in Spain?

Arduino Pro Micro - switch off LEDs

Grover's algorithm - DES circuit as oracle?



Finding the path in a graph from A to B then back to A with a minimum of shared edges



The 2019 Stack Overflow Developer Survey Results Are In
Announcing the arrival of Valued Associate #679: Cesar Manara
Planned maintenance scheduled April 17/18, 2019 at 00:00UTC (8:00pm US/Eastern)Finding a “not-shortest” path between two verticesFinding all shortest paths between two verticesMaking FindShortestPath a little bit sloppyFinding all simple paths between two vertices in a graphGraphPath: *all* shortest paths for 2 vertices, edge lengths negativeFinding Hamiltonian path in GraphTest if directed graph is connectedHow do I get all possible paths in terms of edges, and not vertices in Mathematica?How to find the shortest path between specified verticesCompleting graph edges “around the world” to GeoPlot an itinerary










6












$begingroup$


the problem is to find cycle from A to B back to A, so that the path B-A would use minimum edges from path A-B. The graph is undirected and can have cycles.



The paths don't have to be shortest, they just need to use the least amount of already used edges on the way from src -> dst. Basically, I always want to take different path back from dst to src, or at least with minimum already used edges on src -> dst.



Example



Graph is undirected, this is just for representing how the path goes.



enter image description here



Node 0 is src and node 4 is dst.



Solution is given bY



src -> dst = 0 -> 2 -> 3 -> 4



dst -> src = 4 -> 5 -> 3 -> 2 -> 1 -> 0



The least possible shared edges in this case is one (edge 2 - 3 )



I was thinking about finding all paths from A to B, then comparing each pair and then choosing the pair with least common edges, but there is probably better approach.










share|improve this question









New contributor




daewo147 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.







$endgroup$











  • $begingroup$
    Please give a number of concrete examples. Does the length of the paths matter at all? Do you just want to find a cycle that includes both A and B? Is the only situation where A->B and B->A may share edges the one where no such cycle exists?
    $endgroup$
    – Szabolcs
    9 hours ago










  • $begingroup$
    Updated. Imagine it as you are travelling but you dont want to use the same path on the way back, if its not possible, then the path with least common edges.
    $endgroup$
    – daewo147
    9 hours ago










  • $begingroup$
    Include a couple of small example graphs please.
    $endgroup$
    – Szabolcs
    9 hours ago










  • $begingroup$
    You might be able to do something like the following (not sure about performance though): For each vertex pair $a,b$ where both directions are allowed replace the edges $a->b,b->a$ with $(a<->h,0),(a<->h,t),(h->b,a->b),(b->h,b->a)$ (the number after the edge indicates the weight, with $h$ being a helper vertex and $t$ being the total of all edges). In the new graph, your task should be the same as looking for the shortest path $a->b->a$ with no repeated edges. I'm not sure how you'd find the path $a->b->a$, maybe @Szabolcs' IGraph/M package has something that can help.
    $endgroup$
    – Lukas Lang
    7 hours ago











  • $begingroup$
    By example, I meant a few copyable examples in Mathematica syntax that can be used for testing, not an image.
    $endgroup$
    – Szabolcs
    5 hours ago















6












$begingroup$


the problem is to find cycle from A to B back to A, so that the path B-A would use minimum edges from path A-B. The graph is undirected and can have cycles.



The paths don't have to be shortest, they just need to use the least amount of already used edges on the way from src -> dst. Basically, I always want to take different path back from dst to src, or at least with minimum already used edges on src -> dst.



Example



Graph is undirected, this is just for representing how the path goes.



enter image description here



Node 0 is src and node 4 is dst.



Solution is given bY



src -> dst = 0 -> 2 -> 3 -> 4



dst -> src = 4 -> 5 -> 3 -> 2 -> 1 -> 0



The least possible shared edges in this case is one (edge 2 - 3 )



I was thinking about finding all paths from A to B, then comparing each pair and then choosing the pair with least common edges, but there is probably better approach.










share|improve this question









New contributor




daewo147 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.







$endgroup$











  • $begingroup$
    Please give a number of concrete examples. Does the length of the paths matter at all? Do you just want to find a cycle that includes both A and B? Is the only situation where A->B and B->A may share edges the one where no such cycle exists?
    $endgroup$
    – Szabolcs
    9 hours ago










  • $begingroup$
    Updated. Imagine it as you are travelling but you dont want to use the same path on the way back, if its not possible, then the path with least common edges.
    $endgroup$
    – daewo147
    9 hours ago










  • $begingroup$
    Include a couple of small example graphs please.
    $endgroup$
    – Szabolcs
    9 hours ago










  • $begingroup$
    You might be able to do something like the following (not sure about performance though): For each vertex pair $a,b$ where both directions are allowed replace the edges $a->b,b->a$ with $(a<->h,0),(a<->h,t),(h->b,a->b),(b->h,b->a)$ (the number after the edge indicates the weight, with $h$ being a helper vertex and $t$ being the total of all edges). In the new graph, your task should be the same as looking for the shortest path $a->b->a$ with no repeated edges. I'm not sure how you'd find the path $a->b->a$, maybe @Szabolcs' IGraph/M package has something that can help.
    $endgroup$
    – Lukas Lang
    7 hours ago











  • $begingroup$
    By example, I meant a few copyable examples in Mathematica syntax that can be used for testing, not an image.
    $endgroup$
    – Szabolcs
    5 hours ago













6












6








6





$begingroup$


the problem is to find cycle from A to B back to A, so that the path B-A would use minimum edges from path A-B. The graph is undirected and can have cycles.



The paths don't have to be shortest, they just need to use the least amount of already used edges on the way from src -> dst. Basically, I always want to take different path back from dst to src, or at least with minimum already used edges on src -> dst.



Example



Graph is undirected, this is just for representing how the path goes.



enter image description here



Node 0 is src and node 4 is dst.



Solution is given bY



src -> dst = 0 -> 2 -> 3 -> 4



dst -> src = 4 -> 5 -> 3 -> 2 -> 1 -> 0



The least possible shared edges in this case is one (edge 2 - 3 )



I was thinking about finding all paths from A to B, then comparing each pair and then choosing the pair with least common edges, but there is probably better approach.










share|improve this question









New contributor




daewo147 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.







$endgroup$




the problem is to find cycle from A to B back to A, so that the path B-A would use minimum edges from path A-B. The graph is undirected and can have cycles.



The paths don't have to be shortest, they just need to use the least amount of already used edges on the way from src -> dst. Basically, I always want to take different path back from dst to src, or at least with minimum already used edges on src -> dst.



Example



Graph is undirected, this is just for representing how the path goes.



enter image description here



Node 0 is src and node 4 is dst.



Solution is given bY



src -> dst = 0 -> 2 -> 3 -> 4



dst -> src = 4 -> 5 -> 3 -> 2 -> 1 -> 0



The least possible shared edges in this case is one (edge 2 - 3 )



I was thinking about finding all paths from A to B, then comparing each pair and then choosing the pair with least common edges, but there is probably better approach.







performance-tuning graphs-and-networks programming






share|improve this question









New contributor




daewo147 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











share|improve this question









New contributor




daewo147 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









share|improve this question




share|improve this question








edited 6 hours ago









m_goldberg

88.6k873200




88.6k873200






New contributor




daewo147 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









asked 9 hours ago









daewo147daewo147

312




312




New contributor




daewo147 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.





New contributor





daewo147 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






daewo147 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











  • $begingroup$
    Please give a number of concrete examples. Does the length of the paths matter at all? Do you just want to find a cycle that includes both A and B? Is the only situation where A->B and B->A may share edges the one where no such cycle exists?
    $endgroup$
    – Szabolcs
    9 hours ago










  • $begingroup$
    Updated. Imagine it as you are travelling but you dont want to use the same path on the way back, if its not possible, then the path with least common edges.
    $endgroup$
    – daewo147
    9 hours ago










  • $begingroup$
    Include a couple of small example graphs please.
    $endgroup$
    – Szabolcs
    9 hours ago










  • $begingroup$
    You might be able to do something like the following (not sure about performance though): For each vertex pair $a,b$ where both directions are allowed replace the edges $a->b,b->a$ with $(a<->h,0),(a<->h,t),(h->b,a->b),(b->h,b->a)$ (the number after the edge indicates the weight, with $h$ being a helper vertex and $t$ being the total of all edges). In the new graph, your task should be the same as looking for the shortest path $a->b->a$ with no repeated edges. I'm not sure how you'd find the path $a->b->a$, maybe @Szabolcs' IGraph/M package has something that can help.
    $endgroup$
    – Lukas Lang
    7 hours ago











  • $begingroup$
    By example, I meant a few copyable examples in Mathematica syntax that can be used for testing, not an image.
    $endgroup$
    – Szabolcs
    5 hours ago
















  • $begingroup$
    Please give a number of concrete examples. Does the length of the paths matter at all? Do you just want to find a cycle that includes both A and B? Is the only situation where A->B and B->A may share edges the one where no such cycle exists?
    $endgroup$
    – Szabolcs
    9 hours ago










  • $begingroup$
    Updated. Imagine it as you are travelling but you dont want to use the same path on the way back, if its not possible, then the path with least common edges.
    $endgroup$
    – daewo147
    9 hours ago










  • $begingroup$
    Include a couple of small example graphs please.
    $endgroup$
    – Szabolcs
    9 hours ago










  • $begingroup$
    You might be able to do something like the following (not sure about performance though): For each vertex pair $a,b$ where both directions are allowed replace the edges $a->b,b->a$ with $(a<->h,0),(a<->h,t),(h->b,a->b),(b->h,b->a)$ (the number after the edge indicates the weight, with $h$ being a helper vertex and $t$ being the total of all edges). In the new graph, your task should be the same as looking for the shortest path $a->b->a$ with no repeated edges. I'm not sure how you'd find the path $a->b->a$, maybe @Szabolcs' IGraph/M package has something that can help.
    $endgroup$
    – Lukas Lang
    7 hours ago











  • $begingroup$
    By example, I meant a few copyable examples in Mathematica syntax that can be used for testing, not an image.
    $endgroup$
    – Szabolcs
    5 hours ago















$begingroup$
Please give a number of concrete examples. Does the length of the paths matter at all? Do you just want to find a cycle that includes both A and B? Is the only situation where A->B and B->A may share edges the one where no such cycle exists?
$endgroup$
– Szabolcs
9 hours ago




$begingroup$
Please give a number of concrete examples. Does the length of the paths matter at all? Do you just want to find a cycle that includes both A and B? Is the only situation where A->B and B->A may share edges the one where no such cycle exists?
$endgroup$
– Szabolcs
9 hours ago












$begingroup$
Updated. Imagine it as you are travelling but you dont want to use the same path on the way back, if its not possible, then the path with least common edges.
$endgroup$
– daewo147
9 hours ago




$begingroup$
Updated. Imagine it as you are travelling but you dont want to use the same path on the way back, if its not possible, then the path with least common edges.
$endgroup$
– daewo147
9 hours ago












$begingroup$
Include a couple of small example graphs please.
$endgroup$
– Szabolcs
9 hours ago




$begingroup$
Include a couple of small example graphs please.
$endgroup$
– Szabolcs
9 hours ago












$begingroup$
You might be able to do something like the following (not sure about performance though): For each vertex pair $a,b$ where both directions are allowed replace the edges $a->b,b->a$ with $(a<->h,0),(a<->h,t),(h->b,a->b),(b->h,b->a)$ (the number after the edge indicates the weight, with $h$ being a helper vertex and $t$ being the total of all edges). In the new graph, your task should be the same as looking for the shortest path $a->b->a$ with no repeated edges. I'm not sure how you'd find the path $a->b->a$, maybe @Szabolcs' IGraph/M package has something that can help.
$endgroup$
– Lukas Lang
7 hours ago





$begingroup$
You might be able to do something like the following (not sure about performance though): For each vertex pair $a,b$ where both directions are allowed replace the edges $a->b,b->a$ with $(a<->h,0),(a<->h,t),(h->b,a->b),(b->h,b->a)$ (the number after the edge indicates the weight, with $h$ being a helper vertex and $t$ being the total of all edges). In the new graph, your task should be the same as looking for the shortest path $a->b->a$ with no repeated edges. I'm not sure how you'd find the path $a->b->a$, maybe @Szabolcs' IGraph/M package has something that can help.
$endgroup$
– Lukas Lang
7 hours ago













$begingroup$
By example, I meant a few copyable examples in Mathematica syntax that can be used for testing, not an image.
$endgroup$
– Szabolcs
5 hours ago




$begingroup$
By example, I meant a few copyable examples in Mathematica syntax that can be used for testing, not an image.
$endgroup$
– Szabolcs
5 hours ago










2 Answers
2






active

oldest

votes


















4












$begingroup$

If the graph is 2-edge-connected then it's easy: find a path A->B, delete it, then find one B->A in the remaining graph.



verticesToEdges[verts_] := UndirectedEdge @@@ Partition[verts, 2, 1]

findABCycle[g_, a_, b_] :=
With[path1 = verticesToEdges@FindShortestPath[g, a, b],
Join[path1,
verticesToEdges@FindShortestPath[EdgeDelete[g, path1], b, a]]
]


Demo:



SeedRandom[123]
g = RandomGraph[10, 20, VertexLabels -> Automatic];

a = 7; b = 8;
HighlightGraph[g, findABCycle[g, a, b], a, b]


enter image description here



If the graph is not bi-edge-connected, we must break it into bi-edge-connected components and do the operation on each component. The edges not in any of these components are called bridges. These are the ones that may need to be repeated (if they fall on the path between A and B).



bridges[g_] :=
Complement[
Sort /@ EdgeList[g],
Flatten[Sort /@ EdgeList@Subgraph[g, #] & /@ KEdgeConnectedComponents[g, 2]]
]


(Note: IGraph/M has the faster and more convenient IGBridges.)



Demo:



g = Graph[1 [UndirectedEdge] 2, 2 [UndirectedEdge] 3, 3 [UndirectedEdge] 4, 
1 [UndirectedEdge] 4, 2 [UndirectedEdge] 4, 3 [UndirectedEdge] 5,
5 [UndirectedEdge] 6, 6 [UndirectedEdge] 7, 7 [UndirectedEdge] 8,
5 [UndirectedEdge] 8, VertexLabels -> Automatic]


enter image description here



(Note: I actually constructed this graph in IGraph/M using IGShorthand["1-2-3-4-1,2-4,3-5-6-7-8-5"]. So much more convenient!)



The bridge is 3-5.



bridgeList = bridges[g]


enter image description here



Let us choose A and B:



a = 1; b = 6;


Find a shortest path:



path = verticesToEdges@FindShortestPath[g, a, b]


enter image description here



Any bridges along the path will need to be traversed twice, no matter what. We now separate the edges along this path into bridges and non-bridges, then determine at which vertices we are jumping from one bi-edge-connected component to the next.



ClearAll[bridgeQ]
bridgeQ[e_] := bridgeQ[e] = MemberQ[Join[bridgeList, Reverse /@ bridgeList], e]

segments = GroupBy[path, bridgeQ]


enter image description here



jumps = Level[segments[True], 2]

(* 3, 5 *)


Find A->B path in bi-connected components:



directionAB = 
verticesToEdges@FindShortestPath[g, ##] & @@@ Partition[
Join[a, jumps, b],
2
]


enter image description here



Now the opposite way:



g2 = EdgeDelete[g, Flatten[directionAB]];

directionBA = verticesToEdges@FindShortestPath[g2, ##] & @@@ Partition[
Reverse@Join[a, jumps, b],
2
]


enter image description here



Now put it all together:



Flatten@Riffle[directionAB, segments[True]],
Riffle[directionBA, Reverse /@ segments[True]]


enter image description here



HighlightGraph[g, result, a, b, VertexSize -> Medium]


enter image description here




Wrap it all up:



findAvoidingRoundtrip[g_, a_, b_] := 
Module[bridgeList, bridgeQ, path, segments, jumps, directionAB, directionBA, g2,
bridgeList = bridges[g];
path = verticesToEdges@FindShortestPath[g, a, b];

Set[bridgeQ[#], True] & /@ Join[bridgeList, Reverse /@ bridgeList];
bridgeQ[_] = False;

segments = GroupBy[path, bridgeQ];

jumps = Level[segments[True], 2];

directionAB =
verticesToEdges@FindShortestPath[g, ##] & @@@
Partition[Join[a, jumps, b], 2];
g2 = EdgeDelete[g, Flatten[directionAB]];
directionBA =
verticesToEdges@FindShortestPath[g2, ##] & @@@
Partition[Reverse@Join[a, jumps, b], 2];

Flatten@Riffle[directionAB, segments[True]],
Riffle[directionBA, Reverse /@ segments[True]]
]


Here's a demo on a larger graph. This time I will use IGraph/M for constructing the example, simply for convenience.



Generate a nice graph suitable for this problem:



bigGraph = GridGraph[10, 10];
bigGraph =
SetProperty[bigGraph, VertexCoordinates -> GraphEmbedding[bigGraph]];

IGSeedRandom[12]
g = IGTakeSubgraph[bigGraph, IGRandomEdgeWalk[bigGraph, 1, 100],
VertexLabels -> Automatic]


enter image description here



Highlight the path:



a = 72; b = 56;
HighlightGraph[
g,
Join[findAvoidingRoundtrip[g, a, b], a, b],
GraphHighlightStyle -> "Thick"
]


enter image description here



findAvoidingRoundtrip[g, a, b]


enter image description here






share|improve this answer











$endgroup$




















    3












    $begingroup$

    The idea is to construct a new graph G2 where all edges that are already used in the forward path are given a large weight. Then we look for a return path in this new graph by using FindShortestPath. This shortest path will try to use as few of the high-weight edges as possible.



    Start with a random graph G and a given forward path between A and B:



    G = RandomGraph[UniformGraphDistribution[200, 300]];
    A = 1;
    B = 2;
    forwardPath = FindShortestPath[G, A, B];


    First, convert the forward path (list of vertices) to a list of edges, using Szabolcs' helper function verticesToEdges:



    verticesToEdges[verts_] := UndirectedEdge @@@ Partition[verts, 2, 1]
    forwardEdges = verticesToEdges[forwardPath];


    Next, construct a graph where the edges of the forward path have a large weight (here the square of the total number of edges in the graph G), all with lots of help from Szabolcs:



    G2 = SetProperty[G, EdgeWeight ->
    Thread[Join[forwardEdges, Reverse/@forwardEdges] -> Length[EdgeRules[G]]^2]];


    Notice that we're working around a bug here: quoting Szabolcs, "if when setting edge weights, an undirected edge is specified in the reverse direction compared to how it appears in the path, the edge weight will not be set."



    Finally, compute the return path as the shortest path in this edge-weighted graph G2:



    returnPath = FindShortestPath[G2, B, A];


    Make a nice plot (with more help from Szabolcs):



    returnEdges = verticesToEdges[returnPath];
    Pforward = HighlightGraph[G, Style[forwardEdges, Green, Thickness[0.01]]];
    Preturn = HighlightGraph[G, Style[returnEdges, Red, Thickness[0.005]]];
    Show[G, Pforward, Preturn, ImageSize -> Full]


    enter image description here



    All together in one function:



    findDifferentReturn[G_Graph, forwardPath_List] := 
    FindShortestPath[
    SetProperty[G,
    EdgeWeight -> Thread[Join[#, Reverse /@ #] &[
    UndirectedEdge @@@ Partition[forwardPath, 2, 1]]
    -> Length[EdgeRules[G]]^2]],
    Last[forwardPath], First[forwardPath]]


    Finally, according to the comments by Szabolcs we can use this function to construct a cycle that is optimally avoiding itself:



    findEdgeAvoidingCycle[G_Graph, A_Integer, B_Integer] := 
    With[fp = FindShortestPath[G, A, B],
    fp, findDifferentReturn[G, fp]]


    Try it out with the given example:



    GG = Graph[UndirectedEdge @@@ 0,2, 0,1, 1,2, 2,3, 3,4, 3,5, 4,5]

    findEdgeAvoidingCycle[GG, 0, 4]



    0, 2, 3, 4, 4, 5, 3, 2, 1, 0







    share|improve this answer











    $endgroup$












    • $begingroup$
      Nice idea! It should be noted that theoretically it is not robust. Suppose that we have a cycle of size larger than 1000 (the weight we use), similar to this: i.stack.imgur.com/Z2777.png Of course, in practice this won't be an issue: just set a much larger weight, e.g. 10^10.
      $endgroup$
      – Szabolcs
      5 hours ago










    • $begingroup$
      Good point @Szabolcs , I edited the code to reflect this point.
      $endgroup$
      – Roman
      5 hours ago










    • $begingroup$
      @Szabolcs my code is quite clumsy, do you have any ideas for cleaning it up? Is there a way of constructing G2 from G by re-weighting the edges instead of going through the whole reconstruction?
      $endgroup$
      – Roman
      5 hours ago










    • $begingroup$
      Well, it should be possible to make it much simpler because this syntax is supposed to work: SetProperty[graph, EdgeWeight -> edge1 -> 2, edge2 -> 3]. Except that it does not work if the edge is not given in the same order as it appears in the graph! Thus this fails: gr = Graph[1 <-> 2, 2 <-> 3]; SetProperty[gr, EdgeWeight -> 3 [UndirectedEdge] 2 -> 10] If I used UndirectedEdge[2,3] -> 10 then it would work.
      $endgroup$
      – Szabolcs
      5 hours ago






    • 1




      $begingroup$
      @Szabolcs Right, I completely missed the fact that the graph is undirected (otherwise, it will most likely be more complicated) - the "example" given in the question is really confusing... (since it shows a weighted, directed graph while the question is about an unweighted, undirected graph). Anyway, thank you for pointing out the proper way to think about it :)
      $endgroup$
      – Lukas Lang
      2 hours ago












    Your Answer








    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "387"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: false,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: null,
    bindNavPrevention: true,
    postfix: "",
    imageUploader:
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    ,
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );






    daewo147 is a new contributor. Be nice, and check out our Code of Conduct.









    draft saved

    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fmathematica.stackexchange.com%2fquestions%2f195114%2ffinding-the-path-in-a-graph-from-a-to-b-then-back-to-a-with-a-minimum-of-shared%23new-answer', 'question_page');

    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    4












    $begingroup$

    If the graph is 2-edge-connected then it's easy: find a path A->B, delete it, then find one B->A in the remaining graph.



    verticesToEdges[verts_] := UndirectedEdge @@@ Partition[verts, 2, 1]

    findABCycle[g_, a_, b_] :=
    With[path1 = verticesToEdges@FindShortestPath[g, a, b],
    Join[path1,
    verticesToEdges@FindShortestPath[EdgeDelete[g, path1], b, a]]
    ]


    Demo:



    SeedRandom[123]
    g = RandomGraph[10, 20, VertexLabels -> Automatic];

    a = 7; b = 8;
    HighlightGraph[g, findABCycle[g, a, b], a, b]


    enter image description here



    If the graph is not bi-edge-connected, we must break it into bi-edge-connected components and do the operation on each component. The edges not in any of these components are called bridges. These are the ones that may need to be repeated (if they fall on the path between A and B).



    bridges[g_] :=
    Complement[
    Sort /@ EdgeList[g],
    Flatten[Sort /@ EdgeList@Subgraph[g, #] & /@ KEdgeConnectedComponents[g, 2]]
    ]


    (Note: IGraph/M has the faster and more convenient IGBridges.)



    Demo:



    g = Graph[1 [UndirectedEdge] 2, 2 [UndirectedEdge] 3, 3 [UndirectedEdge] 4, 
    1 [UndirectedEdge] 4, 2 [UndirectedEdge] 4, 3 [UndirectedEdge] 5,
    5 [UndirectedEdge] 6, 6 [UndirectedEdge] 7, 7 [UndirectedEdge] 8,
    5 [UndirectedEdge] 8, VertexLabels -> Automatic]


    enter image description here



    (Note: I actually constructed this graph in IGraph/M using IGShorthand["1-2-3-4-1,2-4,3-5-6-7-8-5"]. So much more convenient!)



    The bridge is 3-5.



    bridgeList = bridges[g]


    enter image description here



    Let us choose A and B:



    a = 1; b = 6;


    Find a shortest path:



    path = verticesToEdges@FindShortestPath[g, a, b]


    enter image description here



    Any bridges along the path will need to be traversed twice, no matter what. We now separate the edges along this path into bridges and non-bridges, then determine at which vertices we are jumping from one bi-edge-connected component to the next.



    ClearAll[bridgeQ]
    bridgeQ[e_] := bridgeQ[e] = MemberQ[Join[bridgeList, Reverse /@ bridgeList], e]

    segments = GroupBy[path, bridgeQ]


    enter image description here



    jumps = Level[segments[True], 2]

    (* 3, 5 *)


    Find A->B path in bi-connected components:



    directionAB = 
    verticesToEdges@FindShortestPath[g, ##] & @@@ Partition[
    Join[a, jumps, b],
    2
    ]


    enter image description here



    Now the opposite way:



    g2 = EdgeDelete[g, Flatten[directionAB]];

    directionBA = verticesToEdges@FindShortestPath[g2, ##] & @@@ Partition[
    Reverse@Join[a, jumps, b],
    2
    ]


    enter image description here



    Now put it all together:



    Flatten@Riffle[directionAB, segments[True]],
    Riffle[directionBA, Reverse /@ segments[True]]


    enter image description here



    HighlightGraph[g, result, a, b, VertexSize -> Medium]


    enter image description here




    Wrap it all up:



    findAvoidingRoundtrip[g_, a_, b_] := 
    Module[bridgeList, bridgeQ, path, segments, jumps, directionAB, directionBA, g2,
    bridgeList = bridges[g];
    path = verticesToEdges@FindShortestPath[g, a, b];

    Set[bridgeQ[#], True] & /@ Join[bridgeList, Reverse /@ bridgeList];
    bridgeQ[_] = False;

    segments = GroupBy[path, bridgeQ];

    jumps = Level[segments[True], 2];

    directionAB =
    verticesToEdges@FindShortestPath[g, ##] & @@@
    Partition[Join[a, jumps, b], 2];
    g2 = EdgeDelete[g, Flatten[directionAB]];
    directionBA =
    verticesToEdges@FindShortestPath[g2, ##] & @@@
    Partition[Reverse@Join[a, jumps, b], 2];

    Flatten@Riffle[directionAB, segments[True]],
    Riffle[directionBA, Reverse /@ segments[True]]
    ]


    Here's a demo on a larger graph. This time I will use IGraph/M for constructing the example, simply for convenience.



    Generate a nice graph suitable for this problem:



    bigGraph = GridGraph[10, 10];
    bigGraph =
    SetProperty[bigGraph, VertexCoordinates -> GraphEmbedding[bigGraph]];

    IGSeedRandom[12]
    g = IGTakeSubgraph[bigGraph, IGRandomEdgeWalk[bigGraph, 1, 100],
    VertexLabels -> Automatic]


    enter image description here



    Highlight the path:



    a = 72; b = 56;
    HighlightGraph[
    g,
    Join[findAvoidingRoundtrip[g, a, b], a, b],
    GraphHighlightStyle -> "Thick"
    ]


    enter image description here



    findAvoidingRoundtrip[g, a, b]


    enter image description here






    share|improve this answer











    $endgroup$

















      4












      $begingroup$

      If the graph is 2-edge-connected then it's easy: find a path A->B, delete it, then find one B->A in the remaining graph.



      verticesToEdges[verts_] := UndirectedEdge @@@ Partition[verts, 2, 1]

      findABCycle[g_, a_, b_] :=
      With[path1 = verticesToEdges@FindShortestPath[g, a, b],
      Join[path1,
      verticesToEdges@FindShortestPath[EdgeDelete[g, path1], b, a]]
      ]


      Demo:



      SeedRandom[123]
      g = RandomGraph[10, 20, VertexLabels -> Automatic];

      a = 7; b = 8;
      HighlightGraph[g, findABCycle[g, a, b], a, b]


      enter image description here



      If the graph is not bi-edge-connected, we must break it into bi-edge-connected components and do the operation on each component. The edges not in any of these components are called bridges. These are the ones that may need to be repeated (if they fall on the path between A and B).



      bridges[g_] :=
      Complement[
      Sort /@ EdgeList[g],
      Flatten[Sort /@ EdgeList@Subgraph[g, #] & /@ KEdgeConnectedComponents[g, 2]]
      ]


      (Note: IGraph/M has the faster and more convenient IGBridges.)



      Demo:



      g = Graph[1 [UndirectedEdge] 2, 2 [UndirectedEdge] 3, 3 [UndirectedEdge] 4, 
      1 [UndirectedEdge] 4, 2 [UndirectedEdge] 4, 3 [UndirectedEdge] 5,
      5 [UndirectedEdge] 6, 6 [UndirectedEdge] 7, 7 [UndirectedEdge] 8,
      5 [UndirectedEdge] 8, VertexLabels -> Automatic]


      enter image description here



      (Note: I actually constructed this graph in IGraph/M using IGShorthand["1-2-3-4-1,2-4,3-5-6-7-8-5"]. So much more convenient!)



      The bridge is 3-5.



      bridgeList = bridges[g]


      enter image description here



      Let us choose A and B:



      a = 1; b = 6;


      Find a shortest path:



      path = verticesToEdges@FindShortestPath[g, a, b]


      enter image description here



      Any bridges along the path will need to be traversed twice, no matter what. We now separate the edges along this path into bridges and non-bridges, then determine at which vertices we are jumping from one bi-edge-connected component to the next.



      ClearAll[bridgeQ]
      bridgeQ[e_] := bridgeQ[e] = MemberQ[Join[bridgeList, Reverse /@ bridgeList], e]

      segments = GroupBy[path, bridgeQ]


      enter image description here



      jumps = Level[segments[True], 2]

      (* 3, 5 *)


      Find A->B path in bi-connected components:



      directionAB = 
      verticesToEdges@FindShortestPath[g, ##] & @@@ Partition[
      Join[a, jumps, b],
      2
      ]


      enter image description here



      Now the opposite way:



      g2 = EdgeDelete[g, Flatten[directionAB]];

      directionBA = verticesToEdges@FindShortestPath[g2, ##] & @@@ Partition[
      Reverse@Join[a, jumps, b],
      2
      ]


      enter image description here



      Now put it all together:



      Flatten@Riffle[directionAB, segments[True]],
      Riffle[directionBA, Reverse /@ segments[True]]


      enter image description here



      HighlightGraph[g, result, a, b, VertexSize -> Medium]


      enter image description here




      Wrap it all up:



      findAvoidingRoundtrip[g_, a_, b_] := 
      Module[bridgeList, bridgeQ, path, segments, jumps, directionAB, directionBA, g2,
      bridgeList = bridges[g];
      path = verticesToEdges@FindShortestPath[g, a, b];

      Set[bridgeQ[#], True] & /@ Join[bridgeList, Reverse /@ bridgeList];
      bridgeQ[_] = False;

      segments = GroupBy[path, bridgeQ];

      jumps = Level[segments[True], 2];

      directionAB =
      verticesToEdges@FindShortestPath[g, ##] & @@@
      Partition[Join[a, jumps, b], 2];
      g2 = EdgeDelete[g, Flatten[directionAB]];
      directionBA =
      verticesToEdges@FindShortestPath[g2, ##] & @@@
      Partition[Reverse@Join[a, jumps, b], 2];

      Flatten@Riffle[directionAB, segments[True]],
      Riffle[directionBA, Reverse /@ segments[True]]
      ]


      Here's a demo on a larger graph. This time I will use IGraph/M for constructing the example, simply for convenience.



      Generate a nice graph suitable for this problem:



      bigGraph = GridGraph[10, 10];
      bigGraph =
      SetProperty[bigGraph, VertexCoordinates -> GraphEmbedding[bigGraph]];

      IGSeedRandom[12]
      g = IGTakeSubgraph[bigGraph, IGRandomEdgeWalk[bigGraph, 1, 100],
      VertexLabels -> Automatic]


      enter image description here



      Highlight the path:



      a = 72; b = 56;
      HighlightGraph[
      g,
      Join[findAvoidingRoundtrip[g, a, b], a, b],
      GraphHighlightStyle -> "Thick"
      ]


      enter image description here



      findAvoidingRoundtrip[g, a, b]


      enter image description here






      share|improve this answer











      $endgroup$















        4












        4








        4





        $begingroup$

        If the graph is 2-edge-connected then it's easy: find a path A->B, delete it, then find one B->A in the remaining graph.



        verticesToEdges[verts_] := UndirectedEdge @@@ Partition[verts, 2, 1]

        findABCycle[g_, a_, b_] :=
        With[path1 = verticesToEdges@FindShortestPath[g, a, b],
        Join[path1,
        verticesToEdges@FindShortestPath[EdgeDelete[g, path1], b, a]]
        ]


        Demo:



        SeedRandom[123]
        g = RandomGraph[10, 20, VertexLabels -> Automatic];

        a = 7; b = 8;
        HighlightGraph[g, findABCycle[g, a, b], a, b]


        enter image description here



        If the graph is not bi-edge-connected, we must break it into bi-edge-connected components and do the operation on each component. The edges not in any of these components are called bridges. These are the ones that may need to be repeated (if they fall on the path between A and B).



        bridges[g_] :=
        Complement[
        Sort /@ EdgeList[g],
        Flatten[Sort /@ EdgeList@Subgraph[g, #] & /@ KEdgeConnectedComponents[g, 2]]
        ]


        (Note: IGraph/M has the faster and more convenient IGBridges.)



        Demo:



        g = Graph[1 [UndirectedEdge] 2, 2 [UndirectedEdge] 3, 3 [UndirectedEdge] 4, 
        1 [UndirectedEdge] 4, 2 [UndirectedEdge] 4, 3 [UndirectedEdge] 5,
        5 [UndirectedEdge] 6, 6 [UndirectedEdge] 7, 7 [UndirectedEdge] 8,
        5 [UndirectedEdge] 8, VertexLabels -> Automatic]


        enter image description here



        (Note: I actually constructed this graph in IGraph/M using IGShorthand["1-2-3-4-1,2-4,3-5-6-7-8-5"]. So much more convenient!)



        The bridge is 3-5.



        bridgeList = bridges[g]


        enter image description here



        Let us choose A and B:



        a = 1; b = 6;


        Find a shortest path:



        path = verticesToEdges@FindShortestPath[g, a, b]


        enter image description here



        Any bridges along the path will need to be traversed twice, no matter what. We now separate the edges along this path into bridges and non-bridges, then determine at which vertices we are jumping from one bi-edge-connected component to the next.



        ClearAll[bridgeQ]
        bridgeQ[e_] := bridgeQ[e] = MemberQ[Join[bridgeList, Reverse /@ bridgeList], e]

        segments = GroupBy[path, bridgeQ]


        enter image description here



        jumps = Level[segments[True], 2]

        (* 3, 5 *)


        Find A->B path in bi-connected components:



        directionAB = 
        verticesToEdges@FindShortestPath[g, ##] & @@@ Partition[
        Join[a, jumps, b],
        2
        ]


        enter image description here



        Now the opposite way:



        g2 = EdgeDelete[g, Flatten[directionAB]];

        directionBA = verticesToEdges@FindShortestPath[g2, ##] & @@@ Partition[
        Reverse@Join[a, jumps, b],
        2
        ]


        enter image description here



        Now put it all together:



        Flatten@Riffle[directionAB, segments[True]],
        Riffle[directionBA, Reverse /@ segments[True]]


        enter image description here



        HighlightGraph[g, result, a, b, VertexSize -> Medium]


        enter image description here




        Wrap it all up:



        findAvoidingRoundtrip[g_, a_, b_] := 
        Module[bridgeList, bridgeQ, path, segments, jumps, directionAB, directionBA, g2,
        bridgeList = bridges[g];
        path = verticesToEdges@FindShortestPath[g, a, b];

        Set[bridgeQ[#], True] & /@ Join[bridgeList, Reverse /@ bridgeList];
        bridgeQ[_] = False;

        segments = GroupBy[path, bridgeQ];

        jumps = Level[segments[True], 2];

        directionAB =
        verticesToEdges@FindShortestPath[g, ##] & @@@
        Partition[Join[a, jumps, b], 2];
        g2 = EdgeDelete[g, Flatten[directionAB]];
        directionBA =
        verticesToEdges@FindShortestPath[g2, ##] & @@@
        Partition[Reverse@Join[a, jumps, b], 2];

        Flatten@Riffle[directionAB, segments[True]],
        Riffle[directionBA, Reverse /@ segments[True]]
        ]


        Here's a demo on a larger graph. This time I will use IGraph/M for constructing the example, simply for convenience.



        Generate a nice graph suitable for this problem:



        bigGraph = GridGraph[10, 10];
        bigGraph =
        SetProperty[bigGraph, VertexCoordinates -> GraphEmbedding[bigGraph]];

        IGSeedRandom[12]
        g = IGTakeSubgraph[bigGraph, IGRandomEdgeWalk[bigGraph, 1, 100],
        VertexLabels -> Automatic]


        enter image description here



        Highlight the path:



        a = 72; b = 56;
        HighlightGraph[
        g,
        Join[findAvoidingRoundtrip[g, a, b], a, b],
        GraphHighlightStyle -> "Thick"
        ]


        enter image description here



        findAvoidingRoundtrip[g, a, b]


        enter image description here






        share|improve this answer











        $endgroup$



        If the graph is 2-edge-connected then it's easy: find a path A->B, delete it, then find one B->A in the remaining graph.



        verticesToEdges[verts_] := UndirectedEdge @@@ Partition[verts, 2, 1]

        findABCycle[g_, a_, b_] :=
        With[path1 = verticesToEdges@FindShortestPath[g, a, b],
        Join[path1,
        verticesToEdges@FindShortestPath[EdgeDelete[g, path1], b, a]]
        ]


        Demo:



        SeedRandom[123]
        g = RandomGraph[10, 20, VertexLabels -> Automatic];

        a = 7; b = 8;
        HighlightGraph[g, findABCycle[g, a, b], a, b]


        enter image description here



        If the graph is not bi-edge-connected, we must break it into bi-edge-connected components and do the operation on each component. The edges not in any of these components are called bridges. These are the ones that may need to be repeated (if they fall on the path between A and B).



        bridges[g_] :=
        Complement[
        Sort /@ EdgeList[g],
        Flatten[Sort /@ EdgeList@Subgraph[g, #] & /@ KEdgeConnectedComponents[g, 2]]
        ]


        (Note: IGraph/M has the faster and more convenient IGBridges.)



        Demo:



        g = Graph[1 [UndirectedEdge] 2, 2 [UndirectedEdge] 3, 3 [UndirectedEdge] 4, 
        1 [UndirectedEdge] 4, 2 [UndirectedEdge] 4, 3 [UndirectedEdge] 5,
        5 [UndirectedEdge] 6, 6 [UndirectedEdge] 7, 7 [UndirectedEdge] 8,
        5 [UndirectedEdge] 8, VertexLabels -> Automatic]


        enter image description here



        (Note: I actually constructed this graph in IGraph/M using IGShorthand["1-2-3-4-1,2-4,3-5-6-7-8-5"]. So much more convenient!)



        The bridge is 3-5.



        bridgeList = bridges[g]


        enter image description here



        Let us choose A and B:



        a = 1; b = 6;


        Find a shortest path:



        path = verticesToEdges@FindShortestPath[g, a, b]


        enter image description here



        Any bridges along the path will need to be traversed twice, no matter what. We now separate the edges along this path into bridges and non-bridges, then determine at which vertices we are jumping from one bi-edge-connected component to the next.



        ClearAll[bridgeQ]
        bridgeQ[e_] := bridgeQ[e] = MemberQ[Join[bridgeList, Reverse /@ bridgeList], e]

        segments = GroupBy[path, bridgeQ]


        enter image description here



        jumps = Level[segments[True], 2]

        (* 3, 5 *)


        Find A->B path in bi-connected components:



        directionAB = 
        verticesToEdges@FindShortestPath[g, ##] & @@@ Partition[
        Join[a, jumps, b],
        2
        ]


        enter image description here



        Now the opposite way:



        g2 = EdgeDelete[g, Flatten[directionAB]];

        directionBA = verticesToEdges@FindShortestPath[g2, ##] & @@@ Partition[
        Reverse@Join[a, jumps, b],
        2
        ]


        enter image description here



        Now put it all together:



        Flatten@Riffle[directionAB, segments[True]],
        Riffle[directionBA, Reverse /@ segments[True]]


        enter image description here



        HighlightGraph[g, result, a, b, VertexSize -> Medium]


        enter image description here




        Wrap it all up:



        findAvoidingRoundtrip[g_, a_, b_] := 
        Module[bridgeList, bridgeQ, path, segments, jumps, directionAB, directionBA, g2,
        bridgeList = bridges[g];
        path = verticesToEdges@FindShortestPath[g, a, b];

        Set[bridgeQ[#], True] & /@ Join[bridgeList, Reverse /@ bridgeList];
        bridgeQ[_] = False;

        segments = GroupBy[path, bridgeQ];

        jumps = Level[segments[True], 2];

        directionAB =
        verticesToEdges@FindShortestPath[g, ##] & @@@
        Partition[Join[a, jumps, b], 2];
        g2 = EdgeDelete[g, Flatten[directionAB]];
        directionBA =
        verticesToEdges@FindShortestPath[g2, ##] & @@@
        Partition[Reverse@Join[a, jumps, b], 2];

        Flatten@Riffle[directionAB, segments[True]],
        Riffle[directionBA, Reverse /@ segments[True]]
        ]


        Here's a demo on a larger graph. This time I will use IGraph/M for constructing the example, simply for convenience.



        Generate a nice graph suitable for this problem:



        bigGraph = GridGraph[10, 10];
        bigGraph =
        SetProperty[bigGraph, VertexCoordinates -> GraphEmbedding[bigGraph]];

        IGSeedRandom[12]
        g = IGTakeSubgraph[bigGraph, IGRandomEdgeWalk[bigGraph, 1, 100],
        VertexLabels -> Automatic]


        enter image description here



        Highlight the path:



        a = 72; b = 56;
        HighlightGraph[
        g,
        Join[findAvoidingRoundtrip[g, a, b], a, b],
        GraphHighlightStyle -> "Thick"
        ]


        enter image description here



        findAvoidingRoundtrip[g, a, b]


        enter image description here







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited 5 hours ago

























        answered 5 hours ago









        SzabolcsSzabolcs

        164k14448948




        164k14448948





















            3












            $begingroup$

            The idea is to construct a new graph G2 where all edges that are already used in the forward path are given a large weight. Then we look for a return path in this new graph by using FindShortestPath. This shortest path will try to use as few of the high-weight edges as possible.



            Start with a random graph G and a given forward path between A and B:



            G = RandomGraph[UniformGraphDistribution[200, 300]];
            A = 1;
            B = 2;
            forwardPath = FindShortestPath[G, A, B];


            First, convert the forward path (list of vertices) to a list of edges, using Szabolcs' helper function verticesToEdges:



            verticesToEdges[verts_] := UndirectedEdge @@@ Partition[verts, 2, 1]
            forwardEdges = verticesToEdges[forwardPath];


            Next, construct a graph where the edges of the forward path have a large weight (here the square of the total number of edges in the graph G), all with lots of help from Szabolcs:



            G2 = SetProperty[G, EdgeWeight ->
            Thread[Join[forwardEdges, Reverse/@forwardEdges] -> Length[EdgeRules[G]]^2]];


            Notice that we're working around a bug here: quoting Szabolcs, "if when setting edge weights, an undirected edge is specified in the reverse direction compared to how it appears in the path, the edge weight will not be set."



            Finally, compute the return path as the shortest path in this edge-weighted graph G2:



            returnPath = FindShortestPath[G2, B, A];


            Make a nice plot (with more help from Szabolcs):



            returnEdges = verticesToEdges[returnPath];
            Pforward = HighlightGraph[G, Style[forwardEdges, Green, Thickness[0.01]]];
            Preturn = HighlightGraph[G, Style[returnEdges, Red, Thickness[0.005]]];
            Show[G, Pforward, Preturn, ImageSize -> Full]


            enter image description here



            All together in one function:



            findDifferentReturn[G_Graph, forwardPath_List] := 
            FindShortestPath[
            SetProperty[G,
            EdgeWeight -> Thread[Join[#, Reverse /@ #] &[
            UndirectedEdge @@@ Partition[forwardPath, 2, 1]]
            -> Length[EdgeRules[G]]^2]],
            Last[forwardPath], First[forwardPath]]


            Finally, according to the comments by Szabolcs we can use this function to construct a cycle that is optimally avoiding itself:



            findEdgeAvoidingCycle[G_Graph, A_Integer, B_Integer] := 
            With[fp = FindShortestPath[G, A, B],
            fp, findDifferentReturn[G, fp]]


            Try it out with the given example:



            GG = Graph[UndirectedEdge @@@ 0,2, 0,1, 1,2, 2,3, 3,4, 3,5, 4,5]

            findEdgeAvoidingCycle[GG, 0, 4]



            0, 2, 3, 4, 4, 5, 3, 2, 1, 0







            share|improve this answer











            $endgroup$












            • $begingroup$
              Nice idea! It should be noted that theoretically it is not robust. Suppose that we have a cycle of size larger than 1000 (the weight we use), similar to this: i.stack.imgur.com/Z2777.png Of course, in practice this won't be an issue: just set a much larger weight, e.g. 10^10.
              $endgroup$
              – Szabolcs
              5 hours ago










            • $begingroup$
              Good point @Szabolcs , I edited the code to reflect this point.
              $endgroup$
              – Roman
              5 hours ago










            • $begingroup$
              @Szabolcs my code is quite clumsy, do you have any ideas for cleaning it up? Is there a way of constructing G2 from G by re-weighting the edges instead of going through the whole reconstruction?
              $endgroup$
              – Roman
              5 hours ago










            • $begingroup$
              Well, it should be possible to make it much simpler because this syntax is supposed to work: SetProperty[graph, EdgeWeight -> edge1 -> 2, edge2 -> 3]. Except that it does not work if the edge is not given in the same order as it appears in the graph! Thus this fails: gr = Graph[1 <-> 2, 2 <-> 3]; SetProperty[gr, EdgeWeight -> 3 [UndirectedEdge] 2 -> 10] If I used UndirectedEdge[2,3] -> 10 then it would work.
              $endgroup$
              – Szabolcs
              5 hours ago






            • 1




              $begingroup$
              @Szabolcs Right, I completely missed the fact that the graph is undirected (otherwise, it will most likely be more complicated) - the "example" given in the question is really confusing... (since it shows a weighted, directed graph while the question is about an unweighted, undirected graph). Anyway, thank you for pointing out the proper way to think about it :)
              $endgroup$
              – Lukas Lang
              2 hours ago
















            3












            $begingroup$

            The idea is to construct a new graph G2 where all edges that are already used in the forward path are given a large weight. Then we look for a return path in this new graph by using FindShortestPath. This shortest path will try to use as few of the high-weight edges as possible.



            Start with a random graph G and a given forward path between A and B:



            G = RandomGraph[UniformGraphDistribution[200, 300]];
            A = 1;
            B = 2;
            forwardPath = FindShortestPath[G, A, B];


            First, convert the forward path (list of vertices) to a list of edges, using Szabolcs' helper function verticesToEdges:



            verticesToEdges[verts_] := UndirectedEdge @@@ Partition[verts, 2, 1]
            forwardEdges = verticesToEdges[forwardPath];


            Next, construct a graph where the edges of the forward path have a large weight (here the square of the total number of edges in the graph G), all with lots of help from Szabolcs:



            G2 = SetProperty[G, EdgeWeight ->
            Thread[Join[forwardEdges, Reverse/@forwardEdges] -> Length[EdgeRules[G]]^2]];


            Notice that we're working around a bug here: quoting Szabolcs, "if when setting edge weights, an undirected edge is specified in the reverse direction compared to how it appears in the path, the edge weight will not be set."



            Finally, compute the return path as the shortest path in this edge-weighted graph G2:



            returnPath = FindShortestPath[G2, B, A];


            Make a nice plot (with more help from Szabolcs):



            returnEdges = verticesToEdges[returnPath];
            Pforward = HighlightGraph[G, Style[forwardEdges, Green, Thickness[0.01]]];
            Preturn = HighlightGraph[G, Style[returnEdges, Red, Thickness[0.005]]];
            Show[G, Pforward, Preturn, ImageSize -> Full]


            enter image description here



            All together in one function:



            findDifferentReturn[G_Graph, forwardPath_List] := 
            FindShortestPath[
            SetProperty[G,
            EdgeWeight -> Thread[Join[#, Reverse /@ #] &[
            UndirectedEdge @@@ Partition[forwardPath, 2, 1]]
            -> Length[EdgeRules[G]]^2]],
            Last[forwardPath], First[forwardPath]]


            Finally, according to the comments by Szabolcs we can use this function to construct a cycle that is optimally avoiding itself:



            findEdgeAvoidingCycle[G_Graph, A_Integer, B_Integer] := 
            With[fp = FindShortestPath[G, A, B],
            fp, findDifferentReturn[G, fp]]


            Try it out with the given example:



            GG = Graph[UndirectedEdge @@@ 0,2, 0,1, 1,2, 2,3, 3,4, 3,5, 4,5]

            findEdgeAvoidingCycle[GG, 0, 4]



            0, 2, 3, 4, 4, 5, 3, 2, 1, 0







            share|improve this answer











            $endgroup$












            • $begingroup$
              Nice idea! It should be noted that theoretically it is not robust. Suppose that we have a cycle of size larger than 1000 (the weight we use), similar to this: i.stack.imgur.com/Z2777.png Of course, in practice this won't be an issue: just set a much larger weight, e.g. 10^10.
              $endgroup$
              – Szabolcs
              5 hours ago










            • $begingroup$
              Good point @Szabolcs , I edited the code to reflect this point.
              $endgroup$
              – Roman
              5 hours ago










            • $begingroup$
              @Szabolcs my code is quite clumsy, do you have any ideas for cleaning it up? Is there a way of constructing G2 from G by re-weighting the edges instead of going through the whole reconstruction?
              $endgroup$
              – Roman
              5 hours ago










            • $begingroup$
              Well, it should be possible to make it much simpler because this syntax is supposed to work: SetProperty[graph, EdgeWeight -> edge1 -> 2, edge2 -> 3]. Except that it does not work if the edge is not given in the same order as it appears in the graph! Thus this fails: gr = Graph[1 <-> 2, 2 <-> 3]; SetProperty[gr, EdgeWeight -> 3 [UndirectedEdge] 2 -> 10] If I used UndirectedEdge[2,3] -> 10 then it would work.
              $endgroup$
              – Szabolcs
              5 hours ago






            • 1




              $begingroup$
              @Szabolcs Right, I completely missed the fact that the graph is undirected (otherwise, it will most likely be more complicated) - the "example" given in the question is really confusing... (since it shows a weighted, directed graph while the question is about an unweighted, undirected graph). Anyway, thank you for pointing out the proper way to think about it :)
              $endgroup$
              – Lukas Lang
              2 hours ago














            3












            3








            3





            $begingroup$

            The idea is to construct a new graph G2 where all edges that are already used in the forward path are given a large weight. Then we look for a return path in this new graph by using FindShortestPath. This shortest path will try to use as few of the high-weight edges as possible.



            Start with a random graph G and a given forward path between A and B:



            G = RandomGraph[UniformGraphDistribution[200, 300]];
            A = 1;
            B = 2;
            forwardPath = FindShortestPath[G, A, B];


            First, convert the forward path (list of vertices) to a list of edges, using Szabolcs' helper function verticesToEdges:



            verticesToEdges[verts_] := UndirectedEdge @@@ Partition[verts, 2, 1]
            forwardEdges = verticesToEdges[forwardPath];


            Next, construct a graph where the edges of the forward path have a large weight (here the square of the total number of edges in the graph G), all with lots of help from Szabolcs:



            G2 = SetProperty[G, EdgeWeight ->
            Thread[Join[forwardEdges, Reverse/@forwardEdges] -> Length[EdgeRules[G]]^2]];


            Notice that we're working around a bug here: quoting Szabolcs, "if when setting edge weights, an undirected edge is specified in the reverse direction compared to how it appears in the path, the edge weight will not be set."



            Finally, compute the return path as the shortest path in this edge-weighted graph G2:



            returnPath = FindShortestPath[G2, B, A];


            Make a nice plot (with more help from Szabolcs):



            returnEdges = verticesToEdges[returnPath];
            Pforward = HighlightGraph[G, Style[forwardEdges, Green, Thickness[0.01]]];
            Preturn = HighlightGraph[G, Style[returnEdges, Red, Thickness[0.005]]];
            Show[G, Pforward, Preturn, ImageSize -> Full]


            enter image description here



            All together in one function:



            findDifferentReturn[G_Graph, forwardPath_List] := 
            FindShortestPath[
            SetProperty[G,
            EdgeWeight -> Thread[Join[#, Reverse /@ #] &[
            UndirectedEdge @@@ Partition[forwardPath, 2, 1]]
            -> Length[EdgeRules[G]]^2]],
            Last[forwardPath], First[forwardPath]]


            Finally, according to the comments by Szabolcs we can use this function to construct a cycle that is optimally avoiding itself:



            findEdgeAvoidingCycle[G_Graph, A_Integer, B_Integer] := 
            With[fp = FindShortestPath[G, A, B],
            fp, findDifferentReturn[G, fp]]


            Try it out with the given example:



            GG = Graph[UndirectedEdge @@@ 0,2, 0,1, 1,2, 2,3, 3,4, 3,5, 4,5]

            findEdgeAvoidingCycle[GG, 0, 4]



            0, 2, 3, 4, 4, 5, 3, 2, 1, 0







            share|improve this answer











            $endgroup$



            The idea is to construct a new graph G2 where all edges that are already used in the forward path are given a large weight. Then we look for a return path in this new graph by using FindShortestPath. This shortest path will try to use as few of the high-weight edges as possible.



            Start with a random graph G and a given forward path between A and B:



            G = RandomGraph[UniformGraphDistribution[200, 300]];
            A = 1;
            B = 2;
            forwardPath = FindShortestPath[G, A, B];


            First, convert the forward path (list of vertices) to a list of edges, using Szabolcs' helper function verticesToEdges:



            verticesToEdges[verts_] := UndirectedEdge @@@ Partition[verts, 2, 1]
            forwardEdges = verticesToEdges[forwardPath];


            Next, construct a graph where the edges of the forward path have a large weight (here the square of the total number of edges in the graph G), all with lots of help from Szabolcs:



            G2 = SetProperty[G, EdgeWeight ->
            Thread[Join[forwardEdges, Reverse/@forwardEdges] -> Length[EdgeRules[G]]^2]];


            Notice that we're working around a bug here: quoting Szabolcs, "if when setting edge weights, an undirected edge is specified in the reverse direction compared to how it appears in the path, the edge weight will not be set."



            Finally, compute the return path as the shortest path in this edge-weighted graph G2:



            returnPath = FindShortestPath[G2, B, A];


            Make a nice plot (with more help from Szabolcs):



            returnEdges = verticesToEdges[returnPath];
            Pforward = HighlightGraph[G, Style[forwardEdges, Green, Thickness[0.01]]];
            Preturn = HighlightGraph[G, Style[returnEdges, Red, Thickness[0.005]]];
            Show[G, Pforward, Preturn, ImageSize -> Full]


            enter image description here



            All together in one function:



            findDifferentReturn[G_Graph, forwardPath_List] := 
            FindShortestPath[
            SetProperty[G,
            EdgeWeight -> Thread[Join[#, Reverse /@ #] &[
            UndirectedEdge @@@ Partition[forwardPath, 2, 1]]
            -> Length[EdgeRules[G]]^2]],
            Last[forwardPath], First[forwardPath]]


            Finally, according to the comments by Szabolcs we can use this function to construct a cycle that is optimally avoiding itself:



            findEdgeAvoidingCycle[G_Graph, A_Integer, B_Integer] := 
            With[fp = FindShortestPath[G, A, B],
            fp, findDifferentReturn[G, fp]]


            Try it out with the given example:



            GG = Graph[UndirectedEdge @@@ 0,2, 0,1, 1,2, 2,3, 3,4, 3,5, 4,5]

            findEdgeAvoidingCycle[GG, 0, 4]



            0, 2, 3, 4, 4, 5, 3, 2, 1, 0








            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited 2 hours ago

























            answered 5 hours ago









            RomanRoman

            5,23511131




            5,23511131











            • $begingroup$
              Nice idea! It should be noted that theoretically it is not robust. Suppose that we have a cycle of size larger than 1000 (the weight we use), similar to this: i.stack.imgur.com/Z2777.png Of course, in practice this won't be an issue: just set a much larger weight, e.g. 10^10.
              $endgroup$
              – Szabolcs
              5 hours ago










            • $begingroup$
              Good point @Szabolcs , I edited the code to reflect this point.
              $endgroup$
              – Roman
              5 hours ago










            • $begingroup$
              @Szabolcs my code is quite clumsy, do you have any ideas for cleaning it up? Is there a way of constructing G2 from G by re-weighting the edges instead of going through the whole reconstruction?
              $endgroup$
              – Roman
              5 hours ago










            • $begingroup$
              Well, it should be possible to make it much simpler because this syntax is supposed to work: SetProperty[graph, EdgeWeight -> edge1 -> 2, edge2 -> 3]. Except that it does not work if the edge is not given in the same order as it appears in the graph! Thus this fails: gr = Graph[1 <-> 2, 2 <-> 3]; SetProperty[gr, EdgeWeight -> 3 [UndirectedEdge] 2 -> 10] If I used UndirectedEdge[2,3] -> 10 then it would work.
              $endgroup$
              – Szabolcs
              5 hours ago






            • 1




              $begingroup$
              @Szabolcs Right, I completely missed the fact that the graph is undirected (otherwise, it will most likely be more complicated) - the "example" given in the question is really confusing... (since it shows a weighted, directed graph while the question is about an unweighted, undirected graph). Anyway, thank you for pointing out the proper way to think about it :)
              $endgroup$
              – Lukas Lang
              2 hours ago

















            • $begingroup$
              Nice idea! It should be noted that theoretically it is not robust. Suppose that we have a cycle of size larger than 1000 (the weight we use), similar to this: i.stack.imgur.com/Z2777.png Of course, in practice this won't be an issue: just set a much larger weight, e.g. 10^10.
              $endgroup$
              – Szabolcs
              5 hours ago










            • $begingroup$
              Good point @Szabolcs , I edited the code to reflect this point.
              $endgroup$
              – Roman
              5 hours ago










            • $begingroup$
              @Szabolcs my code is quite clumsy, do you have any ideas for cleaning it up? Is there a way of constructing G2 from G by re-weighting the edges instead of going through the whole reconstruction?
              $endgroup$
              – Roman
              5 hours ago










            • $begingroup$
              Well, it should be possible to make it much simpler because this syntax is supposed to work: SetProperty[graph, EdgeWeight -> edge1 -> 2, edge2 -> 3]. Except that it does not work if the edge is not given in the same order as it appears in the graph! Thus this fails: gr = Graph[1 <-> 2, 2 <-> 3]; SetProperty[gr, EdgeWeight -> 3 [UndirectedEdge] 2 -> 10] If I used UndirectedEdge[2,3] -> 10 then it would work.
              $endgroup$
              – Szabolcs
              5 hours ago






            • 1




              $begingroup$
              @Szabolcs Right, I completely missed the fact that the graph is undirected (otherwise, it will most likely be more complicated) - the "example" given in the question is really confusing... (since it shows a weighted, directed graph while the question is about an unweighted, undirected graph). Anyway, thank you for pointing out the proper way to think about it :)
              $endgroup$
              – Lukas Lang
              2 hours ago
















            $begingroup$
            Nice idea! It should be noted that theoretically it is not robust. Suppose that we have a cycle of size larger than 1000 (the weight we use), similar to this: i.stack.imgur.com/Z2777.png Of course, in practice this won't be an issue: just set a much larger weight, e.g. 10^10.
            $endgroup$
            – Szabolcs
            5 hours ago




            $begingroup$
            Nice idea! It should be noted that theoretically it is not robust. Suppose that we have a cycle of size larger than 1000 (the weight we use), similar to this: i.stack.imgur.com/Z2777.png Of course, in practice this won't be an issue: just set a much larger weight, e.g. 10^10.
            $endgroup$
            – Szabolcs
            5 hours ago












            $begingroup$
            Good point @Szabolcs , I edited the code to reflect this point.
            $endgroup$
            – Roman
            5 hours ago




            $begingroup$
            Good point @Szabolcs , I edited the code to reflect this point.
            $endgroup$
            – Roman
            5 hours ago












            $begingroup$
            @Szabolcs my code is quite clumsy, do you have any ideas for cleaning it up? Is there a way of constructing G2 from G by re-weighting the edges instead of going through the whole reconstruction?
            $endgroup$
            – Roman
            5 hours ago




            $begingroup$
            @Szabolcs my code is quite clumsy, do you have any ideas for cleaning it up? Is there a way of constructing G2 from G by re-weighting the edges instead of going through the whole reconstruction?
            $endgroup$
            – Roman
            5 hours ago












            $begingroup$
            Well, it should be possible to make it much simpler because this syntax is supposed to work: SetProperty[graph, EdgeWeight -> edge1 -> 2, edge2 -> 3]. Except that it does not work if the edge is not given in the same order as it appears in the graph! Thus this fails: gr = Graph[1 <-> 2, 2 <-> 3]; SetProperty[gr, EdgeWeight -> 3 [UndirectedEdge] 2 -> 10] If I used UndirectedEdge[2,3] -> 10 then it would work.
            $endgroup$
            – Szabolcs
            5 hours ago




            $begingroup$
            Well, it should be possible to make it much simpler because this syntax is supposed to work: SetProperty[graph, EdgeWeight -> edge1 -> 2, edge2 -> 3]. Except that it does not work if the edge is not given in the same order as it appears in the graph! Thus this fails: gr = Graph[1 <-> 2, 2 <-> 3]; SetProperty[gr, EdgeWeight -> 3 [UndirectedEdge] 2 -> 10] If I used UndirectedEdge[2,3] -> 10 then it would work.
            $endgroup$
            – Szabolcs
            5 hours ago




            1




            1




            $begingroup$
            @Szabolcs Right, I completely missed the fact that the graph is undirected (otherwise, it will most likely be more complicated) - the "example" given in the question is really confusing... (since it shows a weighted, directed graph while the question is about an unweighted, undirected graph). Anyway, thank you for pointing out the proper way to think about it :)
            $endgroup$
            – Lukas Lang
            2 hours ago





            $begingroup$
            @Szabolcs Right, I completely missed the fact that the graph is undirected (otherwise, it will most likely be more complicated) - the "example" given in the question is really confusing... (since it shows a weighted, directed graph while the question is about an unweighted, undirected graph). Anyway, thank you for pointing out the proper way to think about it :)
            $endgroup$
            – Lukas Lang
            2 hours ago











            daewo147 is a new contributor. Be nice, and check out our Code of Conduct.









            draft saved

            draft discarded


















            daewo147 is a new contributor. Be nice, and check out our Code of Conduct.












            daewo147 is a new contributor. Be nice, and check out our Code of Conduct.











            daewo147 is a new contributor. Be nice, and check out our Code of Conduct.














            Thanks for contributing an answer to Mathematica Stack Exchange!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid


            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.

            Use MathJax to format equations. MathJax reference.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fmathematica.stackexchange.com%2fquestions%2f195114%2ffinding-the-path-in-a-graph-from-a-to-b-then-back-to-a-with-a-minimum-of-shared%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Siegen Nawigatsjuun

            Log på Navigationsmenu

            Log på Navigationsmenu