Package structure

From user perspective, PyRigi follows object-oriented design. The main functionality can be accessed via the methods of Graph, Framework, or the classes inherited from Motion. However, in order to have extendable and maintainable code, most of the algorithms are implemented as functions and wrapped as methods of the corresponding classes. As such, they are suggested by autocompletion tools once an instance, like Graph, is available and therefore easy to search for and use. This approach allows one to implement functionality in separate modules according to the topics, see below.

The modules are considered non-public (they are in folders with a single leading underscore), hence their structure might change in backward incompatible manner.

Graph functionality

Functions implementing graph functionalities accept networkx.Graph as the first parameter and are then wrapped as pyrigi.Graph methods.

For example, consider the method Graph.is_rigid(). In the file pyrigi/graph/graph.py it looks like:

from ._rigidity import generic as generic_rigidity
class Graph(nx.Graph):
    @copy_doc(generic_rigidity.is_rigid)
    def is_rigid(
        self,
        dim: int = 2,
        algorithm: str = "default",
        use_precomputed_pebble_digraph: bool = False,
        prob: float = 0.0001,
    ) -> bool:
        return generic_rigidity.is_rigid(
            self,
            dim=dim,
            algorithm=algorithm,
            use_precomputed_pebble_digraph=use_precomputed_pebble_digraph,
            prob=prob,
        )

As one can see, this method simply calls the function is_rigid located in the file pyrigi/graph/rigidity/generic.py. The decorator @copy_doc copies the docstring from the function. If we now look at the function, we see

def is_rigid(
    graph: nx.Graph,
    dim: int = 2,
    algorithm: str = "default",
    use_precomputed_pebble_digraph: bool = False,
    prob: float = 0.0001,
) -> bool:
    """
    Return whether the graph is ``dim``-rigid.
    ...
    """
    # implementation of the function

As one may notice, the parameters of the function is_rigid are the same as those for the method Graph.is_rigid(), except for the first one, which is of type networkx.Graph and is always called graph.

Therefore, if new graph functionalities are added, they should be implemented as a function accepting networkx.Graph and then wrapped as methods of pyrigi.Graph. The decorator @copy_doc not only copies the docstring but also converts function-style examples to method-style at import time. Therefore, docstrings should be written in function-style, referring to the graph as “the graph” rather than by the parameter name graph.

In the Parameters section of the functions docstrings, the first parameter has to be a bare graph/framework (i.e., without any description), which is removed automatically by @copy_doc (the description would remain, if present).

Writing examples for copy_doc-wrapped functions

Examples in function-style docstrings must follow these rules so copy_doc can invert them to method-style at import time:

  1. No chained instantiation. Assign the graph to a variable first:

    >>> g = graphs.Diamond()
    >>> len(list(all_k_extensions(g, 1, 2, only_non_isomorphic=True)))
    

    Chained calls like all_k_extensions(graphs.Diamond(), ...) are not caught by the regex and will remain in function-style inside the method docstring.

  2. Outer wrappers are allowed (list, len, type, sorted, print, etc.), as long as no argument to the function is itself a function call:

    >>> type(all_extensions(G))          # OK — no nested call in args
    >>> len(list(all_k_extensions(G, 0)))  # OK — linear args
    
  3. For multiline calls, place the graph variable alone on the first continuation line. This is the only multiline pattern that copy_doc can invert:

    >>> print(to_tikz(          # graph variable NOT on this line
    ...     G,                  # graph variable alone here — OK
    ...     layout_type="circular",
    ...     vertex_style="myvertex"))
    

    The following patterns are not converted and must be avoided:

    >>> print(to_tikz(G,        # G on the >>> line without closing paren — NOT handled
    ...     layout_type="circular"))
    

Regarding type hinting, networkx.Graph should be used in the function signature, while pyrigi.Graph should be used in the method signature. This is needed, for example, when a function/method returns a Graph.

Framework functionality

Similarly to the graph case, the functions implementing framework functionalities accept pyrigi.framework.base.FrameworkBase as the first parameter, called framework, and are wrapped as methods of pyrigi.Framework, which is inherited from pyrigi.framework.base.FrameworkBase.

Overview

_utils/
    __init__.py 
    _conversion.py ............................... conversions between data types
    _doc.py .................................. tools for generating documentation
    _graph_alias_mapping.py 
    _input_check.py .................................. functions for input checks
    _zero_check.py ........................ functions for checking symbolic zeros
    linear_algebra.py .............................. functions for linear algebra
    repetable_iterator.py 
    union_find.py 
framework/
    _export/
        __init__.py 
        export.py ............................. functions for export to TikZ, STL
    _plot/
        __init__.py 
        plot.py .......................................... functions for plotting
    _rigidity/
        __init__.py 
        infinitesimal.py ................... functions for infinitesimal rigidity
        matroidal.py ................... functions for framework rigidity matroid
        redundant.py ........................... functions for redundant rigidity
        second_order.py .... functions for prestress stability and 2nd order rig.
        stress.py ........................................ functions for stresses
    _transformations/
        transformations.py ....................... functions like rotate or scale
    __init__.py 
    _general.py ..................................... general framework functions
    base.py ..................................... implementation of FrameworkBase
    conftest.py 
    framework.py .................................... implementation of Framework
graph/
    _constructions/
        constructions.py ................... functions like t-sum or intersection
        extensions.py ................................ functions for k-extensions
    _export/
        __init__.py 
        export.py .................................. functions for export to TikZ
    _flexibility/
        nac/
            __init__.py 
            algorithms.py 
            check.py 
            core.py 
            cycle_detection.py 
            existence.py 
            facade.py 
            mono_classes.py 
            search.py 
            single.py 
            strategies.py 
        __init__.py 
    _other/
        apex.py ....................................... functions for apex graphs
        separating_set.py ................ functions for (stable) separating sets
    _rigidity/
        generic.py ............................... functions for generic rigidity
        global_.py ................................ functions for global rigidity
        matroidal.py ..................... functions for generic rigidity matroid
        realization_counting.py 
        redundant.py ........................... functions for redundant rigidity
    _sparsity/
        _pebble_digraph.py ...................... implementation of PebbleDigraph
        sparsity.py ................................ functions for (k,l)-sparsity
    _utils/
        _input_check.py .................................. input checks for Graph
        utils.py 
    __init__.py 
    _general.py ......................................... general graph functions
    conftest.py 
    graph.py ............................................ implementation of Graph
graph_drawer/
    __init__.py 
    graph_drawer.py ............................... implementation of GraphDrawer
misc/
    __init__.py 
motion/
    __init__.py 
    approximate_motion.py ................... implementation of ApproximateMotion
    motion.py .......................................... implementation of Motion
    parametric_motion.py ..................... implementation of ParametricMotion
__init__.py 
data_type.py .......................................... definitions of data types
exception.py .......................................... definitions of exceptions
frameworkDB.py ........................................... database of frameworks
graphDB.py ................................................... database of graphs
plot_style.py ................................ implementation of Plotstyle(2D/3D)
warning.py .............................................. definitions of warnings