elm-community / graph

Functional Graph Library in Elm.

Home Page:http://package.elm-lang.org/packages/elm-community/graph/latest

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

mapContexts does not apply changes to edges for some nodes.

janwirth opened this issue · comments

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"

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?

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.