PreviousUpNext

15.4.770  src/lib/graph/graph-minor-view.pkg

# graph-minor-view.pkg
#  Graph minor.
#  Allows contraction of nodes.  
#  Remove self-edges during contraction. 
#  
#  -- Allen Leung

# Compiled by:
#     src/lib/graph/graphs.lib

stipulate
    package odg =  oop_digraph;                                         # oop_digraph   is from   src/lib/graph/oop-digraph.pkg
herein

    api Graph_Minor_View {
        #
        minor:  odg::Digraph(N,E,G)                                     # Here N,E,G stand stead for the types of client-package-supplied records associated with (respectively) nodes, edges and graphs.
                ->
                ((N, N, List( odg::Edge( E ) )) -> N)
                ->
                { view:       odg::Digraph(N,E,G),
                  union:     (odg::Node_Id, odg::Node_Id) -> Bool,
                  same:      (odg::Node_Id, odg::Node_Id) -> Bool,
                  partition:  odg::Node_Id -> List( odg::Node_Id )
                };
    };
end;


stipulate
    package djs =  disjoint_sets_with_constant_time_union;              # disjoint_sets_with_constant_time_union        is from   src/lib/src/disjoint-sets-with-constant-time-union.pkg
    package odg =  oop_digraph;                                         # oop_digraph                                   is from   src/lib/graph/oop-digraph.pkg
    package rwv =  sparse_rw_vector;                                    # sparse_rw_vector                              is from   src/lib/src/sparse-rw-vector.pkg
herein

    package   graph_minor_view
    : (weak)  Graph_Minor_View                                          # Graph_Minor_View                              is from   src/lib/graph/graph-minor-view.pkg
    {


        Node (N,E)
            = 
            NODE { key:    Int,
                   data:   N,
                   nodes:  List( odg::Node_Id ),
                   next:   List( odg::Edge( E ) ),
                   prior:   List( odg::Edge( E ) )
                 };


        fun minor (odg::DIGRAPH dig:  odg::Digraph( N, E, G) ) merge_nodes
            =
            { view, union, same, partition }
            where

                fun unimplemented _
                    =
                    raise exception odg::READ_ONLY;

                nnn   =  dig.capacity ();
                table =  rwv::make_rw_vector'(nnn, \\ _ =  raise exception odg::NOT_FOUND);

                fun get n
                    =
                    {   (djs::get (rwv::get (table, n)))
                            ->
                            NODE x;

                        x;
                    };

                dig.forall_nodes 
                    (\\ (n, n')
                        =
                        rwv::set
                          (
                            table,
                            n,
                            djs::make_singleton_disjoint_set
                                (NODE
                                  { key   =>   n,
                                    data  =>   n',
                                    nodes =>  [n],
                                    next  =>  dig.out_edges n,
                                    prior =>  dig.in_edges  n
                                  }
                                )
                          )
                    );

                fun same (i, j)
                    =
                    djs::equal (rwv::get (table, i), rwv::get (table, j));

                fun partition i
                    =
                    .nodes (get i); 

                size  =  REF (dig.size  ());
                order =  REF (dig.order ());

                fun out_edges n =   (get n).next;
                fun in_edges  n =   (get n).prior;

                fun prior n =  map #1 (in_edges  n);
                fun next  n =  map #2 (out_edges n);

                fun nodes ()
                    = 
                    collect (dig.nodes (),[])
                    where
                        found =  rwv::make_rw_vector (10, FALSE);

                        fun collect ((node as (n, _)) ! nodes, nodes')
                                =>
                                if (rwv::get (found, n) )
                                    #
                                    collect (nodes, nodes');
                                else
                                    ns = partition n;
                                    apply  (\\ n = rwv::set (found, n, TRUE))  ns;
                                    collect (nodes, node ! nodes');
                                fi;

                           collect([], nodes')
                               =>
                               nodes';
                        end;
                    end;

                fun edges ()
                    =
                    list::cat (
                        map' (nodes ())
                             (\\ (n, _) =  out_edges n)
                            
                    );

                fun has_edge (i, j)
                    =
                    list::exists
                        (\\ (_, j', _) =  j == j')
                        (out_edges i);

                fun has_node  n
                    =
                    {   rwv::get (table, n);
                        TRUE;
                    }
                    except
                        odg::NOT_FOUND =  FALSE;

                fun node_info n
                    =
                    .data (get n);

                fun forall_nodes f =  apply f (nodes());
                fun forall_edges f =  apply f (edges());

                fun merge (NODE { key=>k1, data=>d1, next=>s1, prior=>p1, nodes=>n1 },
                           NODE { key=>k2, data=>d2, next=>s2, prior=>p2, nodes=>n2 } )
                    =
                    node
                    where

                        fun key i
                            =
                            .key (get i);

                        fun partition ([], others, self)
                                =>
                                (others, self);

                            partition((e as (i, j, _)) ! es, others, self)
                                =>
                                {   k_i = key i;
                                    k_j = key j;

                                    if ((k_i == k1 or k_i == k2) and   
                                        (k_j == k1 or k_j == k2)
                                       )
                                          partition (es, others, e ! self);  
                                    else  partition (es, e ! others, self);
                                    fi;
                                };
                        end;

                        my (s, s') =  partition (s1 @ s2,  [], []);
                        my (p, p') =  partition (p1 @ p2,  [], []);

                        node = NODE { key   => k1,
                                      data  => merge_nodes (d1, d2, s'),
                                      nodes => n1 @ n2, 
                                      next  => s,
                                      prior  => p
                                    }; 

                        order :=  *order - 1;
                        size  :=  *size - length s';

                    end;

                fun union (i, j)
                    =
                    djs::unify merge (rwv::get (table, i), rwv::get (table, j));

                view =  odg::DIGRAPH
                          {
                            name            => dig.name,
                            graph_info      => dig.graph_info,
                            allot_node_id   => unimplemented,                   # This sucks beyond belief -- total typesafety subversion. If you're not going to implement an API, write a new one dammit.  XXX BUGGO FIXME.
                            add_node        => unimplemented,
                            add_edge        => unimplemented,
                            remove_node     => unimplemented,
                            set_in_edges    => unimplemented,
                            set_out_edges   => unimplemented,
                            set_entries     => unimplemented,
                            set_exits       => unimplemented,
                            garbage_collect => unimplemented,
                            nodes,
                            edges,
                            order           => {. *order; },
                            size            => {. *size; },
                            capacity        => dig.capacity,
                            out_edges,
                            in_edges,
                            next,
                            prior,
                            has_edge,
                            has_node,
                            node_info,
                            entries         => dig.entries,
                            exits           => dig.exits,
                            entry_edges     => dig.entry_edges,
                            exit_edges      => dig.exit_edges,
                            forall_nodes, 
                            forall_edges
                          };
            end;
    };
end;


Comments and suggestions to: bugs@mythryl.org

PreviousUpNext