Mathematica 12.1 introduces edge tagged graph (EdgeTaggedGraph), which is supposed to solve the problem of distinguishability of parallel edges. Unfortunately, the feature is not very well done, and there is no way to guarantee distinguishability. It is allowed that some edges do not have tags at all, or that parallel edges have the very same tag.
Thus, if we were to implement a function which requires that edges be distinguishable, we must check that that is really the case. Since this check will be run every time our function is called, it should be very fast. In Mathematica 12.0 and earlier, which had no edge tagged graphs, one could simply use MultigraphQ. This is an O(1) operation, I assume achieved through caching.
How can I check that all edges of a graph are distinguishable in Mathematica 12.1, with the best possible performance?
My current solution:
nonDistinguishableEdgesQ = MultigraphQ[#] && (Not@EdgeTaggedGraphQ[#] || canonicalEdgeBlock@Not@DuplicateFreeQ@EdgeList[#])&
where canonicalEdgeBlock is from here (a still open question also asking for performance improvements).
I am afraid that unless someone finds an internal function that does this, we are stuck with an O(n) solution. This question is for finding the fastest such solution.
Requirements:
- As fast as possible.
- Must work on all kinds of graphs that Mathematica supports, including mixed graphs.
- It is acceptable (in fact it is practically necessary) for the function to have multiple branches, selecting the fastest possible method for the type of given input graph.
- It is acceptable to use IGraph/M specific functions, such as
IGIndexEdgeList, for the implementation.
This is the current version (I am still experimenting with speeding it up): https://github.com/szhorvat/IGraphM/blob/master/IGraphM/PropertyTransformations.m#L15
Benchmark
Since this is a performance-tuning question, it is appropriate to add a benchmark, so that people can test their attempts. The most important case if tagged graphs where edges are distinguishable. These should be handled as fast as possible.
SeedRandom[99]
g1 = Graph[Range[1000], RandomInteger[{1, 1000}, {50000, 2}]];
tg1 = EdgeTaggedGraph[g1];
g2 = Graph[Range[200], RandomInteger[{1, 200}, {300, 2}]];
tg2 = EdgeTaggedGraph[g2];
The following implementation relies on internal IGraph/M functions, therefore you need to install IGraph/M before it can be used.
nonDistinguishableEdgesQ = MultigraphQ[#] && Not[EdgeTaggedGraphQ[#] && distinguishableTaggedEdgesQ[#]]&;
distinguishableTaggedEdgesQ[graph_] :=
If[MixedGraphQ[graph],
IGraphM`PackageScope`canonicalEdgeBlock@DuplicateFreeQ@EdgeList[graph]
,
If[UndirectedGraphQ[graph],
DuplicateFreeQ@Transpose@Append[
Transpose[IGraphM`PackageScope`igraphGlobal@"edgeListSortPairs"[IGIndexEdgeList[graph]]],
EdgeTags[graph]
],
DuplicateFreeQ@Transpose@Append[
Transpose[IGIndexEdgeList[graph]],
EdgeTags[graph]
]
]
]
Benchmark results:
RepeatedTiming[nonDistinguishableEdgesQ[tg1], 5]
(* {0.0095, False} *)
RepeatedTiming[nonDistinguishableEdgesQ[tg2], 5]
(* {0.000069, False} *)
nonDistinctEQ=MatchQ[{___,Repeated[UndirectedEdge[OrderlessPatternSequence[a_,b_],c___], {2}],___}]@Sort[EdgeList[#]]&;any better? – kglr Mar 30 '20 at 00:35a<->bandb<->amay not be consecutive in the edge list, even after sorting. ThereforeRepeatedwill not match. – Szabolcs Mar 30 '20 at 06:30nonDistinctEdgesQ=Not@*DuplicateFreeQ@*Map[SubsetMap[Sort,#, ;;2]&]@*(EdgeList[#,_UndirectedEdge]&)? – kglr Mar 30 '20 at 07:22Sort[EdgeList[#]]&toSortBy[Sort[#[[;;2]]]&][EdgeList[#]]&innonDistinctEQ? – kglr Mar 31 '20 at 07:13IGConnectedQ, which takes less time, despite the inefficient conversion from Mathematica to igraph format (!!). (Don't compare it toConnectedGraphQ, as that one caches the result.) – Szabolcs Mar 31 '20 at 11:11