mapContexts does not apply changes to edges for some nodes.
janwirth opened this issue · comments
janwirth commented
When I mapContexts
and modify the incoming / outgoing, this only works for some nodes. In the example below, the edge changes for node 1 are completely ignored. Is the sole purpose of mapContext to be able to read outgoing / incoming edges but not to be able to modify them?
test =
let
g = Graph.fromNodesAndEdges
[Graph.Node 1 "1", Graph.Node 2 "2"] [Graph.Edge 1 2 "label1-2", Graph.Edge 2 1 "label2-1"]
-- |> Debug.log "g"
|> Graph.mapContexts (\ctx ->
let
_ = Debug.log "ctxin" ctx.incoming
_ = Debug.log "ctxout" ctx.outgoing
in
if ctx.node.id == 1
then {ctx | incoming = IntDict.empty, outgoing = IntDict.empty}
|> Debug.log "emptied"
else ctx
)
|> Graph.mapContexts (\ctx ->
let
_ = Debug.log "ctxinafter" ctx.incoming
_ = Debug.log "ctxoutafter" ctx.outgoing
in
ctx
)
|> Graph.mapContexts (\ctx ->
if ctx.node.id == 2
then {ctx | incoming = IntDict.empty, outgoing = IntDict.empty}
|> Debug.log "emptied"
else ctx
)
|> Graph.mapContexts (\ctx ->
let
_ = Debug.log "ctxinafterClean2" ctx.incoming
_ = Debug.log "ctxoutafterClean2" ctx.outgoing
in
ctx
)
in
"ok"
Sebastian Graf commented
You remove "label1-2"
from the outgoing
set of node 1, but not from the incoming
set of node 2. For the API to work, you have to apply your changes symmetrically.
That's a shortcoming of the documentation. Could you open a PR to fix that?
janwirth commented
Dropping this explanation from the elm slack here:
[mthiems](https://app.slack.com/team/UHKJ3NGAF) [12 days ago](https://elmlang.slack.com/archives/C0CJ3SBBM/p1645620769656609?thread_ts=1645615865.828029&cid=C0CJ3SBBM)
The data structure for elm-community/graph has inherent redundancy -- every edge in the incoming dict for a given node shows up again in the outgoing dict for the node at the other end of the edge, and vice-versa. In your example above, the first mapContexts is trying to say that node 1 has no edges into nor out of it, while node 2 still has edges in both directions between itself and node 1; this mapping is not consistent. Since mapContexts works using by using fold to reconstruct the graph, the results will depend on the order of processing the nodes in a situation like your example. In the "emptying 1" example, first node 1 has no edges, then says node 2 has birdirectional edges with node 1 and reconstructs a valid graph (thus putting the edges into node 1 as well). In the "emptying 2" example, first node 1 has edges with node 2 (so the valid graph is constructed accordingly) and then node 2 is updated to say that it has no edges -- so the edges are removed from node 1 as well to make a valid graph.
So you can use mapContexts to modify graphs, but you'd have to make consistent edge changes between each pair of nodes during the mapping. Otherwise you'll get order-dependent results. Practically speaking I think it means it may not be the ideal way to "rewire" a graph.