Unfortunately I don’t have great suggestions for a work around. To compound matters, the problem actually exists under Linux as well but is latent. I.e. a future change in Linux could expose the same issue there.
The underlying problem is a classic treating-pointer-values-as-numbers situation, which affects iteration order. The values you get from heap-allocated pointers are not the same across executions due to things like ASLR. On Linux (and in particular under Glibc) things mostly work out because heap pointers are generally increasing for sequential allocations. We actually fixed the problem previously but the fix caused a regression in a Graphviz tool fdp and we had to revert it. I have not had a chance to debug the fdp breakage but the code looked pretty hairy.
“Why is Graphviz designed that way?” Well at the time this code was written, things like ASLR did not yet exist. Memory was precious and promiscuously passing values between pointer and int types was a common practice pre-ISO-C. One of the more senior maintainers may be able to provide further details.
Anyway, that was probably more information than you wanted to know and not particularly helpful to you. Deterministic execution is a fairly baseline property, and I’m sorry we’ve ended up in this situation where Graphviz lacks it. You may be able to achieve some determinism by disabling ASLR and friends, but be aware there are security implications to this.
An exacerbating issue is that your graph does nothing to specify left-to-right sequence for the inner clusters. This is perfectly “legal”, but it leaves dot on its own (so to speak).
The version below adds invisible edges to provide guidance. It also rearranges the sequence of the clusters. Sometimes dot seems to sequence objects “backwards” - in the reverse order that they were specified, so they are now introduced “backwards”.
Please run your loop test. Maybe it will be deterministic.
I appreciated the comments here were kind not harsh.
I wonder if, in situations where we are carelessly treating pointers as numbers, if we can instead use the graph object ID or sequence number, to make the behavior deterministic.
@smattr, thanks for all this information, even if I did not understand everything
At least it will give good orientation for those interested in understanding what is going under the hood.
@steveroush, thanks for your proposition, I tried it but unfortunately, I still have non-deterministic behavior. Few calls to the server with the same file show the problem. I believe that adding parents to constraint the graph as I showed in my previous post is ( so far ) the only way to have deterministic behavior
Yes, I was not meaning to crticize the previous design choices. Most of this was common practice at the time, as far as I have seen in C code bases elsewhere. Unfortunately changes in the surrounding ecosystem have shifted the ground beneath Graphviz.
This is more or less what I did in the original fix. Unfortunately this made fdp very unhappy. It introduces a number of “virtual” objects and then later expects to be able to look them up by pointer address. Unorthodox stuff in fdp is also what’s blocking fixing HTML-like and non-HTML-like strings with the same content cannot coexist (#2089) · Issues · graphviz / graphviz · GitLab IIRC. We reverted the original fix as it wasn’t obvious how to adjust fdp. Since then I have still not had time to debug either problem.
This graph produced the same result 19 times in a row on Windows. It adds two invisible nodes and edges to nail the clusters in the “right” positions. But no guarantees.
[yes, there were many failed ideas]
I like your solution, we still have to create invisible nodes but at least the cost is low.
By the way, I beat you! I’ve got much more than 19 times in a row with the same results