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. Since the docstrings are shown as those of methods, they should be written keeping that in mind, hence not referring to their first parameter, but rather to expressions like “the graph” and not as graph. Moreover, examples in docstrings should be methods of pyrigi.Graph instances, and not functions taking networkx.Graph.

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.

Correct wrapping checks

The test test_signature in test/test_signature.py checks whether the signatures of the methods and the wrapped function match. Hereby, “match” means that the parameters are the same, have the same default values, and have the same type (or inherited type).

The plugin flake8-unused-arguments guarantees that all arguments of each method are indeed used when calling the wrapped function. This plugin is automatically used (calling flake8) once dependences are installed via Poetry.

Overview

_utils/
    __init__.py 
    _conversion.py ............................... conversions between data types
    _doc.py .................................. tools for generating documentation
    _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 
            facade.py 
            mono_classes.py 
            search.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
        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