Skip to content
GitLab
Projects Groups Snippets
  • /
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
    • Contribute to GitLab
  • Sign in / Register
  • graph-tool graph-tool
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
  • Issues 48
    • Issues 48
    • List
    • Boards
    • Service Desk
    • Milestones
  • Merge requests 0
    • Merge requests 0
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
  • Deployments
    • Deployments
    • Environments
    • Releases
  • Monitor
    • Monitor
    • Incidents
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Repository
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar

Please use the issue tracker only to report bugs (i.e. errors in the library that need to be fixed) or feature requests.

For questions about how to compile, install or use the library, please use instead the web forum at https://forum.skewed.de/c/graph-tool.


(If unsure, use the forum first.)


IMPORTANT: When opening new issues, please choose the BUG template from the drop-down menu, and fill out the required information.

  • Tiago Peixoto
  • graph-toolgraph-tool
  • Issues
  • #163
Closed
Open
Issue created Aug 06, 2014 by Tiago Peixoto@count0Owner

graph_union: propagate both external and internal property maps

This is an enhancement proposal that allows to propagate internal and external property maps conveniently. Currently, internal property maps are propagated only if props=None is set (or done by the user). The proposal does not break the current API's behavior, but introduces a new parameter force_propagate_internal_properties. There is also a new example in the doc string that uses the proposal.

#!python

def graph_union(g1, g2, intersection=None, props=None, include=False, force_propagate_internal_properties=False):
    """Return the union of graphs g1 and g2, composed of all edges and vertices
    of g1 and g2, without overlap.

    Parameters
    ----------
    g1 : :class:`~graph_tool.Graph`
       First graph in the union.
    g2 : :class:`~graph_tool.Graph`
       Second graph in the union.
    intersection : :class:`~graph_tool.PropertyMap` (optional, default: ``None``)
       Vertex property map owned by `g1` which maps each of its vertices
       to vertex indexes belonging to `g2`. Negative values mean no mapping
       exists, and thus both vertices in `g1` and `g2` will be present in the
       union graph.
    props : list of tuples of :class:`~graph_tool.PropertyMap` (optional, default: ``None``)
       Each element in this list must be a tuple of two PropertyMap objects. The
       first element must be a property of `g1`, and the second of `g2`. If either
       value is ``None``, an empty map is created. The values of the property
       maps are propagated into the union graph, and returned. If this value is
       ``None`` all internal property maps are propagated.
    include : bool (optional, default: ``False``)
       If true, graph `g2` is inserted into `g1` which is modified. If false, a
       new graph is created, and both graphs remain unmodified.
    force_propagate_internal_properties : bool (optional, default: ``False``)
       If true, propagate internal property maps even if `props` is not ``None``.

    Returns
    -------
    ug : :class:`~graph_tool.Graph`
        The union graph
    props : list of :class:`~graph_tool.PropertyMap` objects
        List of propagated properties.  This is only returned if `props` is not
        empty.

    Examples
    --------

    .. testcode::
       :hide:

       from numpy.random import random, seed
       from pylab import *
       seed(42)
       gt.seed_rng(42)

    >>> g = gt.triangulation(random((300,2)))[0]
    >>> ug = gt.graph_union(g, g)
    >>> uug = gt.graph_union(g, ug)
    >>> pos = gt.sfdp_layout(g)
    >>> gt.graph_draw(g, pos=pos, output_size=(300,300), output="graph_original.pdf")
    <...>

    .. testcode::
       :hide:

       gt.graph_draw(g, pos=pos, output_size=(300,300), output="graph_original.png")

    >>> pos = gt.sfdp_layout(ug)
    >>> gt.graph_draw(ug, pos=pos, output_size=(300,300), output="graph_union.pdf")
    <...>

    .. testcode::
       :hide:

       gt.graph_draw(ug, pos=pos, output_size=(300,300), output="graph_union.png")

    >>> pos = gt.sfdp_layout(uug)
    >>> gt.graph_draw(uug, pos=pos, output_size=(300,300), output="graph_union2.pdf")
    <...>

    .. testcode::
       :hide:

       gt.graph_draw(uug, pos=pos, output_size=(300,300), output="graph_union2.png")


    .. image:: graph_original.*
    .. image:: graph_union.*
    .. image:: graph_union2.*
    

    .. testcode::
       :hide:

       from numpy.random import random, seed
       from pylab import *
       seed(42)
       gt.seed_rng(42)

    >>> g1 = gt.triangulation(random((300,2)))[0]
    >>> g2 = gt.triangulation(random((300,2)))[0]
    >>> p1 = g1.new_vertex_property("bool")
    >>> p1.a = True
    >>> p2 = g2.new_vertex_property("bool")
    >>> p2.a = True
    >>> vcolor = g1.new_vertex_property("string")
    >>> for v in g1.vertices(): vcolor[v] = "red"
    >>> vcolor = g2.new_vertex_property("string")
    >>> for v in g2.vertices(): vcolor[v] = "blue"
    >>> ug, (pu1,pu2) = gt.graph_union(g1, g2, props=[(p1,None),(None,p2)], force_propagate_internal_properties=True)
    >>> g1v = gt.GraphView(ug,vfilt=pu1)
    >>> g2v = gt.GraphView(ug,vfilt=pu2)
    >>> pos = gt.sfdp_layout(ug)
    >>> gt.graph_draw(g, pos=pos, vprops=dict(fill_color=ug.vp['vcolor']), output_size=(300,300), output="graph_union3.pdf")
    <...>

    .. image:: graph_union3.*

    """
    pnames = None
    if (props is None) or (force_propagate_internal_properties):
        if props is None:
          props = []
          pnames = []
        else:
          pnames = [None for x in props]
        for (k, name), p1 in g1.properties.items():
            if k == 'g':
                continue
            p2 = g2.properties.get((k, name), None)
            props.append((p1, p2))
            pnames.append(name)
        for (k, name), p2 in g2.properties.items():
            if k == 'g' or (k, name) in g1.properties:
                continue
            props.append((None, p2))
            pnames.append(name)
        gprops = [[(name, g1.properties[('g', name)]) for name in g1.graph_properties.keys()],
                  [(name, g2.properties[('g', name)]) for name in g2.graph_properties.keys()]]
    if not include:
        g1 = GraphView(g1, skip_properties=True)
        p1s = []
        for i, (p1, p2) in enumerate(props):
            if p1 is None:
                continue
            if p1.key_type() == "v":
                g1.vp[str(i)] = p1
            elif p1.key_type() == "e":
                g1.ep[str(i)] = p1

        g1 = Graph(g1, prune=True)

        for i, (p1, p2) in enumerate(props):
            if p1 is None:
                continue
            if str(i) in g1.vp:
                props[i] = (g1.vp[str(i)], p2)
                del g1.vp[str(i)]
            else:
                props[i] = (g1.ep[str(i)], p2)
                del g1.ep[str(i)]
    else:
        emask, emask_flip = g1.get_edge_filter()
        emask_flipped = False
        if emask is not None and not emask_flip:
            emask.a = not emask.a
            emask_flipped = True
            g1.set_edge_filter(emask, True)

        vmask, vmask_flip = g1.get_vertex_filter()
        vmask_flipped = False
        if vmask is not None and not vmask_flip:
            vmask.a = not vmask.a
            g1.set_vertex_filter(vmask, True)
            vmask_flipped = True

    if intersection is None:
        intersection = g1.new_vertex_property("int32_t")
        intersection.a = 0
    else:
        intersection = intersection.copy("int32_t")
        intersection.a[intersection.a >= 0] += 1
        intersection.a[intersection.a < 0] = 0

    u1 = GraphView(g1, directed=True, skip_properties=True)
    u2 = GraphView(g2, directed=True, skip_properties=True)

    vmap, emap = libgraph_tool_generation.graph_union(u1._Graph__graph,
                                                      u2._Graph__graph,
                                                      _prop("v", g1,
                                                            intersection))

    if include:
        emask, emask_flip = g1.get_edge_filter()
        if emask is not None and emask_flipped:
            emask.a = not emask.a
            g1.set_edge_filter(emask, False)

        vmask, vmask_flip = g1.get_vertex_filter()
        if vmask is not None and vmask_flipped:
            vmask.a = not vmask.a
            g1.set_vertex_filter(vmask, False)

    n_props = []
    for p1, p2 in props:
        if p1 is None:
            p1 = g1.new_property(p2.key_type(), p2.value_type())
        if p2 is None:
            p2 = g2.new_property(p1.key_type(), p1.value_type())
        if not include:
            p1 = g1.copy_property(p1)
        if p2.value_type() != p1.value_type():
            p2 = g2.copy_property(p2, value_type=p1.value_type())
        if p1.key_type() == 'v':
            libgraph_tool_generation.\
                  vertex_property_union(u1._Graph__graph, u2._Graph__graph,
                                        vmap, emap,
                                        _prop(p1.key_type(), g1, p1),
                                        _prop(p2.key_type(), g2, p2))
        else:
            libgraph_tool_generation.\
                  edge_property_union(u1._Graph__graph, u2._Graph__graph,
                                      vmap, emap,
                                      _prop(p1.key_type(), g1, p1),
                                      _prop(p2.key_type(), g2, p2))
        n_props.append(p1)

    if pnames is not None:
        n_n_props = []
        for name, p in zip(pnames, n_props):
            if name is None: 
              n_n_props.append(p)
            else:
              g1.properties[(p.key_type(), name)] = p
        if not include:
            for name, p in gprops[0]:
                g1.graph_properties[name] = p.copy()
        for name, p in gprops[1]:
            if name not in g1.graph_properties:
                g1.graph_properties[name] = p.copy()
        n_props = n_n_props

    if len(n_props) > 0:
        return g1, n_props
    else:
        return g1
Assignee
Assign to
Time tracking