PreviousUpNext

15.4.1050  src/lib/std/graphtree/traitful-graphtree-g.pkg

## traitful-graphtree-g.pkg
#
# See overview comments in
#     src/lib/std/graphtree/traitful-graphtree.api

# Compiled by:
#     src/lib/std/standard.lib

# This generic package gets expanded in:
#     src/lib/std/dot/dot-graphtree.pkg
#     src/lib/std/dot/planar-graphtree.pkg

                                                                                # Traitful_Graphtree    is from   src/lib/std/graphtree/traitful-graphtree.api

stipulate
    package sm  =  string_map;                                                  # string_map            is from   src/lib/src/string-map.pkg
herein

    generic package traitful_graphtree_g (
        #
        Graph_Info;                                                             # E.g. from   src/lib/std/dot/dot-graphtree-traits.pkg
        Edge_Info;                                                              # E.g. from   src/lib/std/dot/dot-graphtree-traits.pkg
        Node_Info;                                                              # E.g. from   src/lib/std/dot/dot-graphtree-traits.pkg

    ): (weak) Traitful_Graphtree
    {
        fun opt_info_fn (THE info, make_default_info) =>  info;
            opt_info_fn (NULL,     make_default_info) =>  make_default_info ();
        end;

        Mapref(X)
            =
            Ref( sm::Map(X) );

        fun drop (d, k)
            =
            d :=  sm::drop (*d, k);


        fun peek (d, k)
            =
            sm::get(*d, k);                                                     # Returns Null_Or(X)


        fun insert (d, k, v)
            =
            d :=  sm::set(*d, k, v);


        fun rm_node_name (d, n)
            =
            d :=  sm::drop (*d, n);

        User_Node_Info  =  Node_Info;
        User_Edge_Info  =  Edge_Info;
        User_Graph_Info =  Graph_Info;

        Node_Info
            =
            {  name:    String, 
               traits:  Mapref( String ),                                       # Arbitrary runtime-specified string key-value pairs.
               info:    User_Node_Info                                          # Application-specific  per-node   record.
            };

        Edge_Info
            =
            { traits:  Mapref( String ),                                        # Arbitrary runtime-specified string key-value pairs.
              info:    User_Edge_Info                                           # Application-specific  per-edge   record.
            };

        Graph_Info
            =
            { info:  User_Graph_Info,                                           # Application-specific  per-graph  record.
              name:  String,
              #
              default_node_traits:  Mapref( String ),
              default_edge_traits:  Mapref( String ),
              traits:               Mapref( String )                            # Arbitrary runtime-specified string key-value pairs.
            };

                                                                                # graphtree_g   is from   src/lib/std/graphtree/graphtree-g.pkg

        package g                                                               # This is -not- part of Traitful_Graphtree api.
            =
            graphtree_g(
                #
                Edge_Info  = Edge_Info;
                Node_Info  = Node_Info;
                Graph_Info = Graph_Info;
            );

        include package   g;

        Node = Node;                                                            # Export 'Node' to external code.
        Edge = Edge;                                                            # Export 'Edge' to external code.

        Traitful_Graph
            =
            TRAITFUL_GRAPH
              { graph:       g::Graph,                                          # This particular sub/graph in the graphtree.
                graphtree:   Graphtree                                          # Information global to the entire tree of sub/graphs.
              }
        also
        Graphtree
            =
            GRAPHTREE
              {
                make_default_graph_info:  Void -> User_Graph_Info,              # Function to initialize  per-graph  application-specific info.
                make_default_edge_info:   Void -> User_Edge_Info,               # Function to initialize  per-edge   application-specific info.
                make_default_node_info:   Void -> User_Node_Info,               # Function to initialize  per-node   application-specific info.
                #
                nodes:   Ref(  sm::Map(  Node  ) ),                             # Map our node  names to node  records.
                graphs:  Ref(  sm::Map(  Traitful_Graph ) )                     # Map sub/graph names to graph records.
              };

        # Fold graphs, edges and nodes into a single type,
        # so that our trait functions get_trait/set_trait/...
        # can operate on any of them:
        #
        Graph_Part
          #
          = GRAPH_PART     Traitful_Graph
          | EDGE_PART      Edge
          | NODE_PART      Node
          #     
          | PROTONODE_PART Traitful_Graph                                       # Holds default traits for newly created nodes.
          | PROTOEDGE_PART Traitful_Graph                                       # Holds default traits for newly created edges.
          ; 



        fun node_name (node: g::Node)
            =
            {   info =  g::node_info_of  node;
                #
                info.name;
            };

        fun graph_name (TRAITFUL_GRAPH { graph, ... } ) = (g::graph_info_of graph).name;
        fun node_count (TRAITFUL_GRAPH { graph, ... } ) =  g::node_count    graph;
        fun edge_count (TRAITFUL_GRAPH { graph, ... } ) =  g::edge_count    graph;

        fun make_graph
            { name:       String,
              info:       Null_Or( User_Graph_Info ),
              #
              make_default_graph_info: Void -> User_Graph_Info,
              make_default_edge_info:  Void ->  User_Edge_Info,
              make_default_node_info:  Void ->  User_Node_Info
            }
            =
            {   graphtree
                    =
                    GRAPHTREE
                      {
                        make_default_graph_info,
                        make_default_edge_info,
                        make_default_node_info,
                        #
                        nodes  =>  REF (sm::empty),
                        graphs =>  REF (sm::empty)
                      };

                info = { name,
                         info => opt_info_fn (info, make_default_graph_info), 
                         #
                         traits =>  REF (sm::empty),
                         #
                         default_node_traits =>  REF (sm::empty),
                         default_edge_traits =>  REF (sm::empty)
                       };

                graph = TRAITFUL_GRAPH
                          { graph =>  g::make_graph info,
                            graphtree
                          };

                graphtree ->  GRAPHTREE { graphs, ... };

                insert (graphs, name, graph);

                graph;
            };


        fun find_subgraph (TRAITFUL_GRAPH { graphtree => GRAPHTREE { graphs, ... }, ... }, name)
            =
            peek (graphs, name);


        fun make_subgraph (g as TRAITFUL_GRAPH { graph, graphtree }, name, opt_info)
            =
            case (find_subgraph (g, name))
                #
                NULL =>
                    {   info = graph_info_of graph;

                        graphtree ->  GRAPHTREE { graphs, make_default_graph_info, ... };

                        info' = { name,
                                  info =>  opt_info_fn (opt_info, make_default_graph_info),
                                  #
                                  traits => REF (*info.traits),
                                  #
                                  default_node_traits =>  REF *info.default_node_traits,
                                  default_edge_traits =>  REF *info.default_edge_traits
                                };

                        subgraph = TRAITFUL_GRAPH { graphtree, graph=>g::make_subgraph (graph, info') };

                        insert (graphs, name, subgraph);

                        subgraph;
                    };

                 _ => raise exception  GRAPHTREE_ERROR "traitful_graphtree::make_subgraph";
            esac;


        fun has_node (TRAITFUL_GRAPH { graph, ... }, node)
            =
            g::has_node (graph, node);

        fun drop_node (g as TRAITFUL_GRAPH { graph, graphtree }, node)
            =
            {   g::drop_node (graph, node);

                if (g::is_root graph)
                    #
                    graphtree ->  GRAPHTREE { nodes, ... };
                    #
                    rm_node_name (nodes, (node_info_of node).name);
                fi;
            };

        fun make_node (g as TRAITFUL_GRAPH { graph, graphtree }, name, opt_info)
            =
            {   graphtree ->   GRAPHTREE { nodes, make_default_node_info, ... };

                traits = *(.default_node_traits (graph_info_of graph));

                info = { name,
                         traits =>  REF traits,
                         info       =>  opt_info_fn (opt_info, make_default_node_info)
                       };

                node = g::make_node (graph, info);

                #  printf "%g: make_node %s\n" (graphName g) name; 

                insert (nodes, name, node);

                node;
            };

        fun get_or_make_node (arg as (g as TRAITFUL_GRAPH { graph, graphtree }, name, _))
            =
            {   graphtree ->  GRAPHTREE { nodes, ... };

                case (peek (nodes, name))
                    #   
                    THE node
                        =>
                        {   if (not (g::has_node (graph, node)))

                                #  printf "%s: put_node %s\n" (graph_name g) name; 

                                put_node (graph, node);
                            fi;

                            node;
                        };

                    NULL => make_node arg;
                esac;
            };

        fun find_node (g as TRAITFUL_GRAPH { graph, graphtree => GRAPHTREE { nodes, ... }}, name)
            =
            case (peek (nodes, name))
                #
                the_node as (THE node)
                    =>
                    if   (g::is_root graph)           the_node;
                    elif (g::has_node (graph, node))  the_node;
                    else                              NULL;
                    fi;
                #
                NULL => NULL;
            esac;

        fun has_edge  (TRAITFUL_GRAPH { graph, ... }, edge) =  g::has_edge  (graph, edge);
        fun drop_edge (TRAITFUL_GRAPH { graph, ... }, edge) =  g::drop_edge (graph, edge);

        fun make_edge { graph => g as TRAITFUL_GRAPH { graph, graphtree, ... }, info, head, tail }
            =
            {   traits = *(graph_info_of graph).default_edge_traits;

                graphtree ->  GRAPHTREE { make_default_edge_info, ... };

                info = { traits =>  REF traits,
                         info   =>  opt_info_fn (info, make_default_edge_info)
                       };

                #  printf "%s: adding edge %s -> %s\n" (graph_name g) (node_name tail) (node_name head); 

                g::make_edge { graph, head, tail, info };
            };

        fun nodes         (TRAITFUL_GRAPH { graph, ... } )   =  g::nodes graph;
        fun nodes_fold  f (TRAITFUL_GRAPH { graph, ... } ) a =  g::nodes_fold f graph a;
        fun nodes_apply f (TRAITFUL_GRAPH { graph, ... } )   =  g::nodes_apply f graph;

        fun edges     (TRAITFUL_GRAPH { graph, ... }      ) =  g::edges graph;
        fun in_edges  (TRAITFUL_GRAPH { graph, ... }, node) =  g::in_edges  (graph, node);
        fun out_edges (TRAITFUL_GRAPH { graph, ... }, node) =  g::out_edges (graph, node);

        fun in_edges_apply  f (TRAITFUL_GRAPH { graph, ... }, n) =  g::in_edges_apply  f (graph, n);
        fun out_edges_apply f (TRAITFUL_GRAPH { graph, ... }, n) =  g::out_edges_apply f (graph, n);

        stipulate

            fun get d k =  peek (d, k);
            fun del d k =  drop (d, k);

            fun ins d (k, v)
                =
                insert (d, k, v);

            fun apply d f = sm::keyed_apply f *d;
            fun count d   = sm::vals_count *d;

            fun do_part f (GRAPH_PART (TRAITFUL_GRAPH { graph, ... } )) =>  f (graph_info_of graph).traits;
                #
                do_part f (EDGE_PART edge) =>  f (edge_info_of edge).traits;
                do_part f (NODE_PART node) =>  f (node_info_of node).traits;
                #
                do_part f (PROTONODE_PART (TRAITFUL_GRAPH { graph, ... } )) =>  f (graph_info_of graph).default_node_traits;
                do_part f (PROTOEDGE_PART (TRAITFUL_GRAPH { graph, ... } )) =>  f (graph_info_of graph).default_edge_traits;
            end;

        herein

            get_trait   =  do_part get;
            set_trait   =  do_part ins;
            drop_trait  =  do_part del;
            trait_apply =  do_part apply;
            count_trait =  do_part count;
        end;

        fun node_info_of  node =   (g::node_info_of node).info;
        fun edge_info_of  edge =   (g::edge_info_of edge).info;

        fun graph_info_of (TRAITFUL_GRAPH { graph, ... } )
            =
             (g::graph_info_of graph).info;

        Node_Info  = User_Node_Info;
        Edge_Info  = User_Edge_Info;
        Graph_Info = User_Graph_Info;

        fun eq_graph
            ( TRAITFUL_GRAPH { graph => g,  ... },
              TRAITFUL_GRAPH { graph => g', ... }
            )
            =
            g::eq_graph (g, g');

    };                                          # generic package traitful_graphtree_g
end;

## COPYRIGHT (c) 1994 AT&T Bell Laboratories.
## Subsequent changes by Jeff Prothero Copyright (c) 2010-2015,
## released per terms of SMLNJ-COPYRIGHT.


Comments and suggestions to: bugs@mythryl.org

PreviousUpNext